diff --git a/src/main/java/org/springframework/data/redis/ClusterRedirectException.java b/src/main/java/org/springframework/data/redis/ClusterRedirectException.java index a8cb91553..f6668c6c8 100644 --- a/src/main/java/org/springframework/data/redis/ClusterRedirectException.java +++ b/src/main/java/org/springframework/data/redis/ClusterRedirectException.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2017 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. @@ -20,8 +20,9 @@ import org.springframework.dao.DataRetrievalFailureException; /** * {@link ClusterRedirectException} indicates that a requested slot is not served by the targeted server but can be * obtained on another one. - * + * * @author Christoph Strobl + * @author Mark Paluch * @since 1.7 */ public class ClusterRedirectException extends DataRetrievalFailureException { @@ -34,11 +35,11 @@ public class ClusterRedirectException extends DataRetrievalFailureException { /** * Creates new {@link ClusterRedirectException}. - * + * * @param slot the slot to redirect to. * @param targetHost the host to redirect to. * @param targetPort the port on the host. - * @param e the root cause from the data access API in use + * @param e the root cause from the data access API in use. */ public ClusterRedirectException(int slot, String targetHost, int targetPort, Throwable e) { @@ -50,27 +51,21 @@ public class ClusterRedirectException extends DataRetrievalFailureException { } /** - * Get slot to go for. - * - * @return + * @return the slot to go for. */ public int getSlot() { return slot; } /** - * Get host serving the slot. - * - * @return + * @return host serving the slot. */ public String getTargetHost() { return host; } /** - * Get port on host serving the slot. - * - * @return + * @return port on host serving the slot. */ public int getTargetPort() { return port; diff --git a/src/main/java/org/springframework/data/redis/ClusterStateFailureException.java b/src/main/java/org/springframework/data/redis/ClusterStateFailureException.java index 003a85457..e0309e064 100644 --- a/src/main/java/org/springframework/data/redis/ClusterStateFailureException.java +++ b/src/main/java/org/springframework/data/redis/ClusterStateFailureException.java @@ -21,7 +21,7 @@ import org.springframework.dao.DataAccessResourceFailureException; * {@link DataAccessResourceFailureException} indicating the current local snapshot of cluster state does no longer * represent the actual remote state. This can happen nodes are removed from cluster, slots get migrated to other nodes * and so on. - * + * * @author Christoph Strobl * @author Mark Paluch * @since 1.7 @@ -32,8 +32,8 @@ public class ClusterStateFailureException extends DataAccessResourceFailureExcep /** * Creates new {@link ClusterStateFailureException}. - * - * @param msg + * + * @param msg the detail message. */ public ClusterStateFailureException(String msg) { super(msg); @@ -41,9 +41,9 @@ public class ClusterStateFailureException extends DataAccessResourceFailureExcep /** * Creates new {@link ClusterStateFailureException}. - * - * @param msg - * @param cause + * + * @param msg the detail message. + * @param cause the nested exception. */ public ClusterStateFailureException(String msg, Throwable cause) { super(msg, cause); diff --git a/src/main/java/org/springframework/data/redis/FallbackExceptionTranslationStrategy.java b/src/main/java/org/springframework/data/redis/FallbackExceptionTranslationStrategy.java index bc90a681c..e5e31414c 100644 --- a/src/main/java/org/springframework/data/redis/FallbackExceptionTranslationStrategy.java +++ b/src/main/java/org/springframework/data/redis/FallbackExceptionTranslationStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2017 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. @@ -20,9 +20,10 @@ import org.springframework.dao.DataAccessException; /** * {@link FallbackExceptionTranslationStrategy} returns {@link RedisSystemException} for unknown {@link Exception}s. - * + * * @author Christoph Strobl * @author Thomas Darimont + * @author Mark Paluch * @since 1.4 */ public class FallbackExceptionTranslationStrategy extends PassThroughExceptionTranslationStrategy { @@ -31,6 +32,10 @@ public class FallbackExceptionTranslationStrategy extends PassThroughExceptionTr super(converter); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.PassThroughExceptionTranslationStrategy#translate(java.lang.Exception) + */ @Override public DataAccessException translate(Exception e) { @@ -40,11 +45,12 @@ public class FallbackExceptionTranslationStrategy extends PassThroughExceptionTr /** * Returns a new {@link RedisSystemException} wrapping the given {@link Exception}. - * - * @param e - * @return + * + * @param e causing exception. + * @return the fallback exception. */ protected RedisSystemException getFallback(Exception e) { return new RedisSystemException("Unknown redis exception", e); } + } diff --git a/src/main/java/org/springframework/data/redis/PassThroughExceptionTranslationStrategy.java b/src/main/java/org/springframework/data/redis/PassThroughExceptionTranslationStrategy.java index 7e27e1793..19655363e 100644 --- a/src/main/java/org/springframework/data/redis/PassThroughExceptionTranslationStrategy.java +++ b/src/main/java/org/springframework/data/redis/PassThroughExceptionTranslationStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2017 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. @@ -17,23 +17,31 @@ package org.springframework.data.redis; import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; +import org.springframework.lang.Nullable; /** * {@link PassThroughExceptionTranslationStrategy} returns {@literal null} for unknown {@link Exception}s. - * + * * @author Christoph Strobl + * @author Mark Paluch * @since 1.4 */ public class PassThroughExceptionTranslationStrategy implements ExceptionTranslationStrategy { - private Converter converter; + private final Converter converter; public PassThroughExceptionTranslationStrategy(Converter converter) { this.converter = converter; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.ExceptionTranslationStrategy#translate(java.lang.Exception) + */ + @Nullable @Override public DataAccessException translate(Exception e) { return this.converter.convert(e); } + } diff --git a/src/main/java/org/springframework/data/redis/RedisConnectionFailureException.java b/src/main/java/org/springframework/data/redis/RedisConnectionFailureException.java index b6478f872..2d2962357 100644 --- a/src/main/java/org/springframework/data/redis/RedisConnectionFailureException.java +++ b/src/main/java/org/springframework/data/redis/RedisConnectionFailureException.java @@ -13,23 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.redis; import org.springframework.dao.DataAccessResourceFailureException; /** * Fatal exception thrown when the Redis connection fails completely. - * + * * @author Mark Pollack */ public class RedisConnectionFailureException extends DataAccessResourceFailureException { + /** + * @param msg the detail message. + */ public RedisConnectionFailureException(String msg) { super(msg); } + /** + * @param msg the detail message. + * @param cause the nested exception. + */ public RedisConnectionFailureException(String msg, Throwable cause) { super(msg, cause); } + } diff --git a/src/main/java/org/springframework/data/redis/RedisSystemException.java b/src/main/java/org/springframework/data/redis/RedisSystemException.java index a7de1a349..86657011e 100644 --- a/src/main/java/org/springframework/data/redis/RedisSystemException.java +++ b/src/main/java/org/springframework/data/redis/RedisSystemException.java @@ -13,19 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.redis; import org.springframework.dao.UncategorizedDataAccessException; /** * Exception thrown when we can't classify a Redis exception into one of Spring generic data access exceptions. - * + * * @author Costin Leau */ public class RedisSystemException extends UncategorizedDataAccessException { + /** + * @param msg the detail message. + * @param cause the root cause from the data access API in use. + */ public RedisSystemException(String msg, Throwable cause) { super(msg, cause); } + } diff --git a/src/main/java/org/springframework/data/redis/TooManyClusterRedirectionsException.java b/src/main/java/org/springframework/data/redis/TooManyClusterRedirectionsException.java index 3d9df7076..692eb40a3 100644 --- a/src/main/java/org/springframework/data/redis/TooManyClusterRedirectionsException.java +++ b/src/main/java/org/springframework/data/redis/TooManyClusterRedirectionsException.java @@ -19,7 +19,7 @@ import org.springframework.dao.DataRetrievalFailureException; /** * {@link DataRetrievalFailureException} thrown when following cluster redirects exceeds the max number of edges. - * + * * @author Christoph Strobl * @since 1.7 */ @@ -29,8 +29,8 @@ public class TooManyClusterRedirectionsException extends DataRetrievalFailureExc /** * Creates new {@link TooManyClusterRedirectionsException}. - * - * @param msg + * + * @param msg the detail message. */ public TooManyClusterRedirectionsException(String msg) { super(msg); @@ -38,9 +38,9 @@ public class TooManyClusterRedirectionsException extends DataRetrievalFailureExc /** * Creates new {@link TooManyClusterRedirectionsException}. - * - * @param msg - * @param cause + * + * @param msg the detail message. + * @param cause the root cause from the data access API in use. */ public TooManyClusterRedirectionsException(String msg, Throwable cause) { super(msg, cause); diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCache.java b/src/main/java/org/springframework/data/redis/cache/RedisCache.java index c0fc359eb..fa7adf255 100644 --- a/src/main/java/org/springframework/data/redis/cache/RedisCache.java +++ b/src/main/java/org/springframework/data/redis/cache/RedisCache.java @@ -292,7 +292,7 @@ public class RedisCache extends AbstractValueAdaptingCache { } throw new IllegalStateException( - "Cannot convert " + source + " to String. Register a Converter or override toString()."); + String.format("Cannot convert %s to String. Register a Converter or override toString().", source)); } private byte[] createAndConvertCacheKey(Object key) { @@ -303,7 +303,7 @@ public class RedisCache extends AbstractValueAdaptingCache { return cacheConfig.getKeyPrefix().orElseGet(() -> name + "::") + key; } - private T valueFromLoader(Object key, Callable valueLoader) { + private static T valueFromLoader(Object key, Callable valueLoader) { try { return valueLoader.call(); diff --git a/src/main/java/org/springframework/data/redis/cache/package-info.java b/src/main/java/org/springframework/data/redis/cache/package-info.java index c79b7ed9e..3b4695da6 100644 --- a/src/main/java/org/springframework/data/redis/cache/package-info.java +++ b/src/main/java/org/springframework/data/redis/cache/package-info.java @@ -1,6 +1,8 @@ /** * Package providing a Redis implementation for Spring - * cache abstraction. + * cache + * abstraction. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.cache; diff --git a/src/main/java/org/springframework/data/redis/config/RedisListenerContainerParser.java b/src/main/java/org/springframework/data/redis/config/RedisListenerContainerParser.java index 0f70998e5..4f8c39541 100644 --- a/src/main/java/org/springframework/data/redis/config/RedisListenerContainerParser.java +++ b/src/main/java/org/springframework/data/redis/config/RedisListenerContainerParser.java @@ -49,6 +49,7 @@ class RedisListenerContainerParser extends AbstractSimpleBeanDefinitionParser { @SuppressWarnings("unchecked") protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + // parse attributes (but replace the value assignment with references) NamedNodeMap attributes = element.getAttributes(); @@ -73,8 +74,7 @@ class RedisListenerContainerParser extends AbstractSimpleBeanDefinitionParser { List listDefs = DomUtils.getChildElementsByTagName(element, "listener"); if (!listDefs.isEmpty()) { - ManagedMap> listeners = new ManagedMap<>( - listDefs.size()); + ManagedMap> listeners = new ManagedMap<>(listDefs.size()); for (Element listElement : listDefs) { Object[] listenerDefinition = parseListener(listElement); listeners.put((BeanDefinition) listenerDefinition[0], @@ -97,6 +97,7 @@ class RedisListenerContainerParser extends AbstractSimpleBeanDefinitionParser { * @return */ private Object[] parseListener(Element element) { + Object[] ret = new Object[2]; BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MessageListenerAdapter.class); diff --git a/src/main/java/org/springframework/data/redis/config/RedisNamespaceHandler.java b/src/main/java/org/springframework/data/redis/config/RedisNamespaceHandler.java index 080681251..f0c117503 100644 --- a/src/main/java/org/springframework/data/redis/config/RedisNamespaceHandler.java +++ b/src/main/java/org/springframework/data/redis/config/RedisNamespaceHandler.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -20,12 +20,13 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /** * {@link NamespaceHandler} for Spring Data Redis namespace. - * + * * @author Costin Leau */ class RedisNamespaceHandler extends NamespaceHandlerSupport { public void init() { + registerBeanDefinitionParser("listener-container", new RedisListenerContainerParser()); registerBeanDefinitionParser("collection", new RedisCollectionParser()); } diff --git a/src/main/java/org/springframework/data/redis/config/package-info.java b/src/main/java/org/springframework/data/redis/config/package-info.java index 0c0b3156c..41ea5708b 100644 --- a/src/main/java/org/springframework/data/redis/config/package-info.java +++ b/src/main/java/org/springframework/data/redis/config/package-info.java @@ -2,4 +2,5 @@ * Namespace and configuration. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.config; 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 95d5ac492..14fb36261 100644 --- a/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java @@ -16,6 +16,7 @@ package org.springframework.data.redis.connection; import java.io.IOException; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.springframework.dao.DataAccessException; @@ -33,7 +34,7 @@ import org.springframework.util.Assert; public abstract class AbstractRedisConnection implements DefaultedRedisConnection { private @Nullable RedisSentinelConfiguration sentinelConfiguration; - private ConcurrentHashMap connectionCache = new ConcurrentHashMap<>(); + private final Map connectionCache = new ConcurrentHashMap<>(); /* * (non-Javadoc) 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 6f32b8289..3ffc724f1 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutionFailureException.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutionFailureException.java @@ -23,8 +23,9 @@ import org.springframework.dao.UncategorizedDataAccessException; /** * Exception thrown when at least one call to a clustered redis environment fails. - * + * * @author Christoph Strobl + * @author Mark Paluch * @since 1.7 */ public class ClusterCommandExecutionFailureException extends UncategorizedDataAccessException { @@ -35,7 +36,7 @@ public class ClusterCommandExecutionFailureException extends UncategorizedDataAc /** * Creates new {@link ClusterCommandExecutionFailureException}. - * + * * @param cause must not be {@literal null}. */ public ClusterCommandExecutionFailureException(Throwable cause) { @@ -44,19 +45,22 @@ public class ClusterCommandExecutionFailureException extends UncategorizedDataAc /** * Creates new {@link ClusterCommandExecutionFailureException}. - * + * * @param causes must not be {@literal empty}. */ 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/ClusterTopology.java b/src/main/java/org/springframework/data/redis/connection/ClusterTopology.java index 7366138c7..1c80b5f9a 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterTopology.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterTopology.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.connection; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; @@ -140,7 +141,7 @@ public class ClusterTopology { } throw new ClusterStateFailureException( - String.format("Could not find master node serving slot %s for key '%s',", slot, key)); + String.format("Could not find master node serving slot %s for key '%s',", slot, Arrays.toString(key))); } /** diff --git a/src/main/java/org/springframework/data/redis/connection/ClusterTopologyProvider.java b/src/main/java/org/springframework/data/redis/connection/ClusterTopologyProvider.java index 74279ed45..ba65c504f 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterTopologyProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterTopologyProvider.java @@ -26,7 +26,7 @@ public interface ClusterTopologyProvider { /** * Get the current known {@link ClusterTopology}. * - * @return never {@null}. + * @return never {@literal null}. */ ClusterTopology getTopology(); diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultSortParameters.java b/src/main/java/org/springframework/data/redis/connection/DefaultSortParameters.java index cb15cf9e7..84ba04803 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultSortParameters.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultSortParameters.java @@ -16,8 +16,11 @@ package org.springframework.data.redis.connection; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import org.springframework.lang.Nullable; + /** * Default implementation for {@link SortParameters}. * @@ -25,11 +28,11 @@ import java.util.List; */ public class DefaultSortParameters implements SortParameters { - private byte[] byPattern; - private Range limit; + private @Nullable byte[] byPattern; + private @Nullable Range limit; private final List getPattern = new ArrayList<>(4); - private Order order; - private Boolean alphabetic; + private @Nullable Order order; + private @Nullable Boolean alphabetic; /** * Constructs a new DefaultSortParameters instance. @@ -45,7 +48,7 @@ public class DefaultSortParameters implements SortParameters { * @param order * @param alphabetic */ - public DefaultSortParameters(Range limit, Order order, Boolean alphabetic) { + public DefaultSortParameters(@Nullable Range limit, @Nullable Order order, @Nullable Boolean alphabetic) { this(null, limit, null, order, alphabetic); } @@ -58,7 +61,8 @@ public class DefaultSortParameters implements SortParameters { * @param order * @param alphabetic */ - public DefaultSortParameters(byte[] byPattern, Range limit, byte[][] getPattern, Order order, Boolean alphabetic) { + public DefaultSortParameters(@Nullable byte[] byPattern, @Nullable Range limit, @Nullable byte[][] getPattern, + @Nullable Order order, @Nullable Boolean alphabetic) { super(); this.byPattern = byPattern; this.limit = limit; @@ -67,6 +71,7 @@ public class DefaultSortParameters implements SortParameters { setGetPattern(getPattern); } + @Nullable public byte[] getByPattern() { return byPattern; } @@ -87,22 +92,22 @@ public class DefaultSortParameters implements SortParameters { return getPattern.toArray(new byte[getPattern.size()][]); } + @Nullable public void addGetPattern(byte[] gPattern) { getPattern.add(gPattern); } - public void setGetPattern(byte[][] gPattern) { + public void setGetPattern(@Nullable byte[][] gPattern) { getPattern.clear(); if (gPattern == null) { return; } - for (byte[] bs : gPattern) { - getPattern.add(bs); - } + Collections.addAll(getPattern, gPattern); } + @Nullable public Order getOrder() { return order; } @@ -111,6 +116,7 @@ public class DefaultSortParameters implements SortParameters { this.order = order; } + @Nullable public Boolean isAlphabetic() { return alphabetic; } 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 6cefa04d0..562afdf48 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -796,8 +796,8 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco * @see org.springframework.data.redis.connection.RedisKeyCommands#rename(byte[], byte[]) */ @Override - public void rename(byte[] oldName, byte[] newName) { - delegate.rename(oldName, newName); + public void rename(byte[] sourceKey, byte[] targetKey) { + delegate.rename(sourceKey, targetKey); } /* @@ -805,8 +805,8 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco * @see org.springframework.data.redis.connection.RedisKeyCommands#renameNX(byte[], byte[]) */ @Override - public Boolean renameNX(byte[] oldName, byte[] newName) { - return convertAndReturn(delegate.renameNX(oldName, newName), identityConverter); + public Boolean renameNX(byte[] sourceKey, byte[] targetKey) { + return convertAndReturn(delegate.renameNX(sourceKey, targetKey), identityConverter); } /* @@ -1129,8 +1129,8 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco * @see org.springframework.data.redis.connection.RedisStringCommands#bitCount(byte[], long, long) */ @Override - public Long bitCount(byte[] key, long begin, long end) { - return convertAndReturn(delegate.bitCount(key, begin, end), identityConverter); + public Long bitCount(byte[] key, long start, long end) { + return convertAndReturn(delegate.bitCount(key, start, end), identityConverter); } /* @@ -2420,8 +2420,8 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco * @see org.springframework.data.redis.connection.StringRedisConnection#bitCount(java.lang.String, long, long) */ @Override - public Long bitCount(String key, long begin, long end) { - return bitCount(serialize(key), begin, end); + public Long bitCount(String key, long start, long end) { + return bitCount(serialize(key), start, end); } /* @@ -3463,7 +3463,8 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco } @SuppressWarnings("unchecked") - private T convertAndReturn(Object value, Converter converter) { + @Nullable + private T convertAndReturn(@Nullable Object value, Converter converter) { if (isFutureConversion()) { @@ -3488,7 +3489,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco } @SuppressWarnings({ "unchecked", "rawtypes" }) - private List convertResults(List results, Queue converters) { + private List convertResults(@Nullable List results, Queue converters) { if (!deserializePipelineAndTxResults || results == null) { return results; } 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 80f79daf5..e2f3bfffe 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringTuple.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringTuple.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -15,21 +15,24 @@ */ package org.springframework.data.redis.connection; +import lombok.EqualsAndHashCode; + import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.connection.StringRedisConnection.StringTuple; /** * Default implementation for {@link StringTuple} interface. - * + * * @author Costin Leau */ +@EqualsAndHashCode(callSuper = true) public class DefaultStringTuple extends DefaultTuple implements StringTuple { private final String valueAsString; /** * Constructs a new DefaultStringTuple instance. - * + * * @param value * @param score */ @@ -41,7 +44,7 @@ public class DefaultStringTuple extends DefaultTuple implements StringTuple { /** * Constructs a new DefaultStringTuple instance. - * + * * @param tuple * @param valueAsString */ @@ -54,28 +57,6 @@ public class DefaultStringTuple extends DefaultTuple implements StringTuple { return valueAsString; } - public int hashCode() { - final int prime = 31; - int result = super.hashCode(); - result = prime * result + ((valueAsString == null) ? 0 : valueAsString.hashCode()); - return result; - } - - public boolean equals(Object obj) { - if (super.equals(obj)) { - if (!(obj instanceof DefaultStringTuple)) - return false; - DefaultStringTuple other = (DefaultStringTuple) obj; - if (valueAsString == null) { - if (other.valueAsString != null) - return false; - } else if (!valueAsString.equals(other.valueAsString)) - return false; - return true; - } - return false; - } - public String toString() { return "DefaultStringTuple[value=" + getValueAsString() + ", score=" + getScore() + "]"; } 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 8de0c63d3..6f3abb5e2 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java @@ -92,15 +92,15 @@ public interface DefaultedRedisConnection extends RedisConnection { /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ @Override @Deprecated - default void rename(byte[] oldName, byte[] newName) { - keyCommands().rename(oldName, newName); + default void rename(byte[] sourceKey, byte[] targetKey) { + keyCommands().rename(sourceKey, targetKey); } /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ @Override @Deprecated - default Boolean renameNX(byte[] oldName, byte[] newName) { - return keyCommands().renameNX(oldName, newName); + default Boolean renameNX(byte[] sourceKey, byte[] targetKey) { + return keyCommands().renameNX(sourceKey, targetKey); } /** @deprecated in favor of {@link RedisConnection#keyCommands()}. */ @@ -318,8 +318,8 @@ public interface DefaultedRedisConnection extends RedisConnection { /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ @Override @Deprecated - default byte[] getRange(byte[] key, long begin, long end) { - return stringCommands().getRange(key, begin, end); + default byte[] getRange(byte[] key, long start, long end) { + return stringCommands().getRange(key, start, end); } /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ @@ -353,8 +353,8 @@ public interface DefaultedRedisConnection extends RedisConnection { /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ @Override @Deprecated - default Long bitCount(byte[] key, long begin, long end) { - return stringCommands().bitCount(key, begin, end); + default Long bitCount(byte[] key, long start, long end) { + return stringCommands().bitCount(key, start, end); } /** @deprecated in favor of {@link RedisConnection#stringCommands()}}. */ diff --git a/src/main/java/org/springframework/data/redis/connection/FutureResult.java b/src/main/java/org/springframework/data/redis/connection/FutureResult.java index 704b5fa52..501edbf9e 100644 --- a/src/main/java/org/springframework/data/redis/connection/FutureResult.java +++ b/src/main/java/org/springframework/data/redis/connection/FutureResult.java @@ -20,12 +20,13 @@ import org.springframework.lang.Nullable; /** * The result of an asynchronous operation - * + * * @author Jennifer Hickey * @author Christoph Strobl + * @author Mark Paluch * @param The data type of the object that holds the future result (usually of type Future) */ -abstract public class FutureResult { +public abstract class FutureResult { protected T resultHolder; @@ -50,7 +51,7 @@ abstract public class FutureResult { /** * Converts the given result if a converter is specified, else returns the result - * + * * @param result The result to convert. Can be {@literal null}. * @return The converted result or {@literal null}. */ @@ -73,7 +74,7 @@ abstract public class FutureResult { /** * Indicates if this result is the status of an operation. Typically status results will be discarded on conversion. - * + * * @return true if this is a status result (i.e. OK) */ public boolean isStatus() { @@ -91,5 +92,5 @@ abstract public class FutureResult { * @return The result of the operation. Can be {@literal null}. */ @Nullable - abstract public Object get(); + public abstract Object get(); } diff --git a/src/main/java/org/springframework/data/redis/connection/PoolException.java b/src/main/java/org/springframework/data/redis/connection/PoolException.java index acc09f724..f594fabc1 100644 --- a/src/main/java/org/springframework/data/redis/connection/PoolException.java +++ b/src/main/java/org/springframework/data/redis/connection/PoolException.java @@ -20,9 +20,10 @@ import org.springframework.lang.Nullable; /** * Exception thrown when there are issues with a resource pool - * + * * @author Jennifer Hickey * @author Christoph Strobl + * @author Mark Paluch */ @SuppressWarnings("serial") public class PoolException extends NestedRuntimeException { @@ -30,19 +31,19 @@ public class PoolException extends NestedRuntimeException { /** * Constructs a new PoolException instance. * - * @param msg - * @param cause + * @param msg the detail message. */ - public PoolException(@Nullable String msg, @Nullable Throwable cause) { - super(msg, cause); + public PoolException(String msg) { + super(msg); } /** * Constructs a new PoolException instance. * - * @param msg + * @param msg the detail message. + * @param cause the nested exception. */ - public PoolException(String msg) { - super(msg); + public PoolException(@Nullable String msg, @Nullable Throwable cause) { + super(msg, cause); } } diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveListCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveListCommands.java index 64125b7a4..db553f8a8 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveListCommands.java @@ -261,7 +261,7 @@ public interface ReactiveListCommands { Flux> lLen(Publisher commands); /** - * Get elements between {@literal begin} and {@literal end} from list at {@literal key}. + * Get elements between {@literal start} and {@literal end} from list at {@literal key}. * * @param key must not be {@literal null}. * @param start @@ -286,7 +286,7 @@ public interface ReactiveListCommands { Flux>> lRange(Publisher commands); /** - * Trim list at {@literal key} to elements between {@literal begin} and {@literal end}. + * Trim list at {@literal key} to elements between {@literal start} and {@literal end}. * * @param key must not be {@literal null}. * @param start diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java index ee680f816..11cdbd14a 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java @@ -519,25 +519,25 @@ public interface ReactiveStringCommands { Flux> append(Publisher commands); /** - * Get a substring of value of {@literal key} between {@literal begin} and {@literal end}. + * Get a substring of value of {@literal key} between {@literal start} and {@literal end}. * * @param key must not be {@literal null}. - * @param begin + * @param start * @param end * @return * @see Redis Documentation: GETRANGE */ - default Mono getRange(ByteBuffer key, long begin, long end) { + default Mono getRange(ByteBuffer key, long start, long end) { Assert.notNull(key, "Key must not be null!"); - return getRange(Mono.just(RangeCommand.key(key).fromIndex(begin).toIndex(end))) // + return getRange(Mono.just(RangeCommand.key(key).fromIndex(start).toIndex(end))) // .next() // .map(ByteBufferResponse::getOutput); } /** - * Get a substring of value of {@literal key} between {@literal begin} and {@literal end}. + * Get a substring of value of {@literal key} between {@literal start} and {@literal end}. * * @param commands must not be {@literal null}. * @return @@ -875,25 +875,25 @@ public interface ReactiveStringCommands { } /** - * Count the number of set bits (population counting) of value stored at {@literal key} between {@literal begin} and + * Count the number of set bits (population counting) of value stored at {@literal key} between {@literal start} and * {@literal end}. * * @param key must not be {@literal null}. - * @param begin + * @param start * @param end * @return * @see Redis Documentation: BITCOUNT */ - default Mono bitCount(ByteBuffer key, long begin, long end) { + default Mono bitCount(ByteBuffer key, long start, long end) { Assert.notNull(key, "Key must not be null!"); - return bitCount(Mono.just(BitCountCommand.bitCount(key).within(new Range<>(begin, end)))).next() + return bitCount(Mono.just(BitCountCommand.bitCount(key).within(new Range<>(start, end)))).next() .map(NumericResponse::getOutput); } /** - * Count the number of set bits (population counting) of value stored at {@literal key} between {@literal begin} and + * Count the number of set bits (population counting) of value stored at {@literal key} between {@literal start} and * {@literal end}. * * @param commands must not be {@literal null}. diff --git a/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java index 809edee5a..923181668 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2017 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 - * + * * http://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. @@ -25,7 +25,7 @@ import org.springframework.lang.Nullable; /** * Key-specific commands supported by Redis. - * + * * @author Costin Leau * @author Christoph Strobl * @author Mark Paluch @@ -92,24 +92,24 @@ public interface RedisKeyCommands { byte[] randomKey(); /** - * Rename key {@code oldName} to {@code newName}. + * Rename key {@code sourceKey} to {@code targetKey}. * - * @param oldName must not be {@literal null}. - * @param newName must not be {@literal null}. + * @param sourceKey must not be {@literal null}. + * @param targetKey must not be {@literal null}. * @see Redis Documentation: RENAME */ - void rename(byte[] oldName, byte[] newName); + void rename(byte[] sourceKey, byte[] targetKey); /** - * Rename key {@code oldName} to {@code newName} only if {@code newName} does not exist. + * Rename key {@code sourceKey} to {@code targetKey} only if {@code targetKey} does not exist. * - * @param oldName must not be {@literal null}. - * @param newName must not be {@literal null}. + * @param sourceKey must not be {@literal null}. + * @param targetKey must not be {@literal null}. * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RENAMENX */ @Nullable - Boolean renameNX(byte[] oldName, byte[] newName); + Boolean renameNX(byte[] sourceKey, byte[] targetKey); /** * Set time to live for given {@code key} in seconds. diff --git a/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java index fbbe7d297..97475be14 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java @@ -21,7 +21,7 @@ import org.springframework.lang.Nullable; /** * List-specific commands supported by Redis. - * + * * @author Costin Leau * @author Christoph Strobl * @author Mark Paluch diff --git a/src/main/java/org/springframework/data/redis/connection/RedisPassword.java b/src/main/java/org/springframework/data/redis/connection/RedisPassword.java index ded000a94..1a6b70d88 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisPassword.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisPassword.java @@ -24,6 +24,7 @@ import java.util.NoSuchElementException; import java.util.Optional; import java.util.function.Function; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -53,7 +54,7 @@ public class RedisPassword { * @param passwordAsString the password as string. * @return the {@link RedisPassword} for {@code passwordAsString}. */ - public static RedisPassword of(String passwordAsString) { + public static RedisPassword of(@Nullable String passwordAsString) { return Optional.ofNullable(passwordAsString) // .filter(StringUtils::hasText) // @@ -67,7 +68,7 @@ public class RedisPassword { * @param passwordAsChars the password as char array. * @return the {@link RedisPassword} for {@code passwordAsChars}. */ - public static RedisPassword of(char[] passwordAsChars) { + public static RedisPassword of(@Nullable char[] passwordAsChars) { return Optional.ofNullable(passwordAsChars) // .filter(it -> !ObjectUtils.isEmpty(passwordAsChars)) // @@ -133,7 +134,7 @@ public class RedisPassword { public Optional toOptional() { if (isPresent()) { - return Optional.ofNullable(get()); + return Optional.of(get()); } return Optional.empty(); diff --git a/src/main/java/org/springframework/data/redis/connection/RedisPubSubCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisPubSubCommands.java index 440e1f742..6ef13d529 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisPubSubCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisPubSubCommands.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2017 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 - * + * * http://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. @@ -19,7 +19,7 @@ import org.springframework.lang.Nullable; /** * PubSub-specific Redis commands. - * + * * @author Costin Leau * @author Mark Paluch * @author Christoph Strobl @@ -46,9 +46,10 @@ public interface RedisPubSubCommands { * * @param channel the channel to publish to. Must not be {@literal null}. * @param message message to publish. Must not be {@literal null}. - * @return the number of clients that received the message. + * @return the number of clients that received the message or {@literal null} when used in pipeline / transaction. * @see Redis Documentation: PUBLISH */ + @Nullable Long publish(byte[] channel, byte[] message); /** diff --git a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java index 6963739ca..172b64680 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java @@ -23,7 +23,7 @@ import org.springframework.lang.Nullable; /** * String/Value-specific commands supported by Redis. - * + * * @author Costin Leau * @author Christoph Strobl * @author Mark Paluch @@ -92,9 +92,10 @@ public interface RedisStringCommands { * * @param key must not be {@literal null}. * @param value must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SETNX */ + @Nullable Boolean setNX(byte[] key, byte[] value); /** @@ -131,17 +132,20 @@ public interface RedisStringCommands { * not exist. * * @param tuple must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: MSETNX */ + @Nullable Boolean mSetNX(Map tuple); /** * Increment an integer value stored as string value of {@code key} by 1. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: INCR */ + @Nullable Long incr(byte[] key); /** @@ -149,9 +153,10 @@ public interface RedisStringCommands { * * @param key must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: INCRBY */ + @Nullable Long incrBy(byte[] key, long value); /** @@ -159,18 +164,20 @@ public interface RedisStringCommands { * * @param key must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: INCRBYFLOAT */ + @Nullable Double incrBy(byte[] key, double value); /** * Decrement an integer value stored as string value of {@code key} by 1. * * @param key must not be {@literal null}. - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: DECR */ + @Nullable Long decr(byte[] key); /** @@ -178,9 +185,10 @@ public interface RedisStringCommands { * * @param key must not be {@literal null}. * @param value - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: DECRBY */ + @Nullable Long decrBy(byte[] key, long value); /** @@ -188,21 +196,23 @@ public interface RedisStringCommands { * * @param key must not be {@literal null}. * @param value must not be {@literal null}. - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: APPEND */ + @Nullable Long append(byte[] key, byte[] value); /** - * Get a substring of value of {@code key} between {@code begin} and {@code end}. + * Get a substring of value of {@code key} between {@code start} and {@code end}. * * @param key must not be {@literal null}. - * @param begin + * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GETRANGE */ - byte[] getRange(byte[] key, long begin, long end); + @Nullable + byte[] getRange(byte[] key, long start, long end); /** * Overwrite parts of {@code key} starting at the specified {@code offset} with given {@code value}. @@ -219,9 +229,10 @@ public interface RedisStringCommands { * * @param key must not be {@literal null}. * @param offset - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GETBIT */ + @Nullable Boolean getBit(byte[] key, long offset); /** @@ -230,31 +241,34 @@ public interface RedisStringCommands { * @param key must not be {@literal null}. * @param offset * @param value - * @return the original bit value stored at {@code offset}. + * @return the original bit value stored at {@code offset} or {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SETBIT */ + @Nullable Boolean setBit(byte[] key, long offset, boolean value); /** * Count the number of set bits (population counting) in value stored at {@code key}. * * @param key must not be {@literal null}. - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: BITCOUNT */ + @Nullable Long bitCount(byte[] key); /** - * Count the number of set bits (population counting) of value stored at {@code key} between {@code begin} and + * Count the number of set bits (population counting) of value stored at {@code key} between {@code start} and * {@code end}. * * @param key must not be {@literal null}. - * @param begin + * @param start * @param end - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: BITCOUNT */ - Long bitCount(byte[] key, long begin, long end); + @Nullable + Long bitCount(byte[] key, long start, long end); /** * Perform bitwise operations between strings. @@ -262,23 +276,25 @@ public interface RedisStringCommands { * @param op must not be {@literal null}. * @param destination must not be {@literal null}. * @param keys must not be {@literal null}. - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: BITOP */ + @Nullable Long bitOp(BitOperation op, byte[] destination, byte[]... keys); /** * Get the length of the value stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: STRLEN */ + @Nullable Long strLen(byte[] key); /** * {@code SET} command arguments for {@code NX}, {@code XX}. - * + * * @author Christoph Strobl * @since 1.7 */ @@ -286,28 +302,28 @@ public interface RedisStringCommands { /** * Do not set any additional command argument. - * + * * @return */ UPSERT, /** * {@code NX} - * + * * @return */ SET_IF_ABSENT, /** * {@code XX} - * + * * @return */ SET_IF_PRESENT; /** * Do not set any additional command argument. - * + * * @return */ public static SetOption upsert() { @@ -316,7 +332,7 @@ public interface RedisStringCommands { /** * {@code XX} - * + * * @return */ public static SetOption ifPresent() { @@ -325,7 +341,7 @@ public interface RedisStringCommands { /** * {@code NX} - * + * * @return */ public static SetOption ifAbsent() { 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 1bb816c17..3eff9d305 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 @@ -102,7 +102,7 @@ abstract public class Converters { Set flags = parseFlags(args); String portPart = hostAndPort[1]; - if (portPart != null && portPart.contains("@")) { + if (portPart.contains("@")) { portPart = portPart.substring(0, portPart.indexOf('@')); } @@ -171,8 +171,7 @@ abstract public class Converters { } } - SlotRange range = new SlotRange(slots); - return range; + return new SlotRange(slots); } }; diff --git a/src/main/java/org/springframework/data/redis/connection/convert/ListConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/ListConverter.java index 7f5b2f176..9a79ef846 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/ListConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/ListConverter.java @@ -47,7 +47,8 @@ public class ListConverter implements Converter, List> { @Override public List convert(List source) { - List results = new ArrayList<>(); + List results = new ArrayList<>(source.size()); + for (S result : source) { results.add(itemConverter.convert(result)); } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/package-info.java b/src/main/java/org/springframework/data/redis/connection/convert/package-info.java index 51cc4f0bf..b58fb458a 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/package-info.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/package-info.java @@ -2,4 +2,5 @@ * Redis specific converters used for sending data and parsing responses. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.connection.convert; 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 06417c3ac..af6838f8d 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterConnection.java @@ -15,8 +15,6 @@ */ package org.springframework.data.redis.connection.jedis; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.lang.Nullable; import redis.clients.jedis.BinaryJedis; import redis.clients.jedis.BinaryJedisPubSub; import redis.clients.jedis.HostAndPort; @@ -38,6 +36,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.PropertyAccessor; import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.ClusterStateFailureException; import org.springframework.data.redis.ExceptionTranslationStrategy; @@ -49,6 +48,7 @@ import org.springframework.data.redis.connection.ClusterCommandExecutor.NodeResu import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -101,7 +101,6 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { } catch (Exception e) { // ignore it and work with the executor default } - } /** @@ -229,7 +228,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { } @Override - public Set keys(RedisClusterNode node, final byte[] pattern) { + public Set keys(RedisClusterNode node, byte[] pattern) { return doGetKeyCommands().keys(node, pattern); } @@ -351,7 +350,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisConnectionCommands#select(int) */ @Override - public void select(final int dbIndex) { + public void select(int dbIndex) { if (dbIndex != 0) { throw new InvalidDataAccessApiUsageException("Cannot SELECT non zero index in cluster mode."); @@ -363,7 +362,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisConnectionCommands#echo(byte[]) */ @Override - public byte[] echo(final byte[] message) { + public byte[] echo(byte[] message) { try { return cluster.echo(message); @@ -404,13 +403,13 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterSetSlot(org.springframework.data.redis.connection.RedisClusterNode, int, org.springframework.data.redis.connection.RedisClusterCommands.AddSlots) */ @Override - public void clusterSetSlot(final RedisClusterNode node, final int slot, final AddSlots mode) { + public void clusterSetSlot(RedisClusterNode node, int slot, AddSlots mode) { Assert.notNull(node, "Node must not be null."); Assert.notNull(mode, "AddSlots mode must not be null."); - final RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(node); - final String nodeId = nodeToUse.getId(); + RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(node); + String nodeId = nodeToUse.getId(); clusterCommandExecutor.executeCommandOnSingleNode((JedisClusterCommandCallback) client -> { @@ -435,7 +434,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterGetKeysInSlot(int, java.lang.Integer) */ @Override - public List clusterGetKeysInSlot(final int slot, final Integer count) { + public List clusterGetKeysInSlot(int slot, Integer count) { RedisClusterNode node = clusterGetNodeForSlot(slot); @@ -452,11 +451,10 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterAddSlots(org.springframework.data.redis.connection.RedisClusterNode, int[]) */ @Override - public void clusterAddSlots(RedisClusterNode node, final int... slots) { + public void clusterAddSlots(RedisClusterNode node, int... slots) { clusterCommandExecutor.executeCommandOnSingleNode( (JedisClusterCommandCallback) client -> client.clusterAddSlots(slots), node); - } /* @@ -476,7 +474,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterCountKeysInSlot(int) */ @Override - public Long clusterCountKeysInSlot(final int slot) { + public Long clusterCountKeysInSlot(int slot) { RedisClusterNode node = clusterGetNodeForSlot(slot); @@ -490,7 +488,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterDeleteSlots(org.springframework.data.redis.connection.RedisClusterNode, int[]) */ @Override - public void clusterDeleteSlots(RedisClusterNode node, final int... slots) { + public void clusterDeleteSlots(RedisClusterNode node, int... slots) { clusterCommandExecutor.executeCommandOnSingleNode( (JedisClusterCommandCallback) client -> client.clusterDelSlots(slots), node); @@ -514,10 +512,10 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterForget(org.springframework.data.redis.connection.RedisClusterNode) */ @Override - public void clusterForget(final RedisClusterNode node) { + public void clusterForget(RedisClusterNode node) { Set nodes = new LinkedHashSet<>(topologyProvider.getTopology().getActiveMasterNodes()); - final RedisClusterNode nodeToRemove = topologyProvider.getTopology().lookup(node); + RedisClusterNode nodeToRemove = topologyProvider.getTopology().lookup(node); nodes.remove(nodeToRemove); clusterCommandExecutor.executeCommandAsyncOnNodes( @@ -529,7 +527,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterMeet(org.springframework.data.redis.connection.RedisClusterNode) */ @Override - public void clusterMeet(final RedisClusterNode node) { + public void clusterMeet(RedisClusterNode node) { Assert.notNull(node, "Cluster node must not be null for CLUSTER MEET command!"); Assert.hasText(node.getHost(), "Node to meet cluster must have a host!"); @@ -544,9 +542,9 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterReplicate(org.springframework.data.redis.connection.RedisClusterNode, org.springframework.data.redis.connection.RedisClusterNode) */ @Override - public void clusterReplicate(final RedisClusterNode master, RedisClusterNode slave) { + public void clusterReplicate(RedisClusterNode master, RedisClusterNode slave) { - final RedisClusterNode masterNode = topologyProvider.getTopology().lookup(master); + RedisClusterNode masterNode = topologyProvider.getTopology().lookup(master); clusterCommandExecutor.executeCommandOnSingleNode( (JedisClusterCommandCallback) client -> client.clusterReplicate(masterNode.getId()), slave); @@ -558,7 +556,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#getClusterSlotForKey(byte[]) */ @Override - public Integer clusterGetSlotForKey(final byte[] key) { + public Integer clusterGetSlotForKey(byte[] key) { return clusterCommandExecutor.executeCommandOnArbitraryNode((JedisClusterCommandCallback) client -> client .clusterKeySlot(JedisConverters.toString(key)).intValue()).getValue(); @@ -594,11 +592,11 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterGetSlaves(org.springframework.data.redis.connection.RedisClusterNode) */ @Override - public Set clusterGetSlaves(final RedisClusterNode master) { + public Set clusterGetSlaves(RedisClusterNode master) { Assert.notNull(master, "Master cannot be null!"); - final RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(master); + RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(master); return JedisConverters.toSetOfRedisClusterNodes(clusterCommandExecutor .executeCommandOnSingleNode( @@ -785,7 +783,8 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { PropertyAccessor accessor = new DirectFieldAccessFallbackBeanWrapper(cluster); this.connectionHandler = accessor.isReadableProperty("connectionHandler") - ? (JedisClusterConnectionHandler) accessor.getPropertyValue("connectionHandler") : null; + ? (JedisClusterConnectionHandler) accessor.getPropertyValue("connectionHandler") + : null; } else { this.connectionHandler = null; } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java index 0fdf08dd4..7cad0b3cd 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHashCommands.java @@ -29,6 +29,7 @@ import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanCursor; import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; /** * @author Christoph Strobl @@ -50,6 +51,10 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public Boolean hSet(byte[] key, byte[] field, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return JedisConverters.toBoolean(connection.getCluster().hset(key, field, value)); } catch (Exception ex) { @@ -64,6 +69,10 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return JedisConverters.toBoolean(connection.getCluster().hsetnx(key, field, value)); } catch (Exception ex) { @@ -78,6 +87,9 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public byte[] hGet(byte[] key, byte[] field) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { return connection.getCluster().hget(key, field); } catch (Exception ex) { @@ -92,6 +104,9 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public List hMGet(byte[] key, byte[]... fields) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(fields, "Fields must not be null!"); + try { return connection.getCluster().hmget(key, fields); } catch (Exception ex) { @@ -106,6 +121,9 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public void hMSet(byte[] key, Map hashes) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(hashes, "Hashes must not be null!"); + try { connection.getCluster().hmset(key, hashes); } catch (Exception ex) { @@ -120,6 +138,9 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public Long hIncrBy(byte[] key, byte[] field, long delta) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { return connection.getCluster().hincrBy(key, field, delta); } catch (Exception ex) { @@ -133,6 +154,10 @@ class JedisClusterHashCommands implements RedisHashCommands { */ @Override public Double hIncrBy(byte[] key, byte[] field, double delta) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { return connection.getCluster().hincrByFloat(key, field, delta); } catch (Exception ex) { @@ -147,6 +172,9 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public Boolean hExists(byte[] key, byte[] field) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { return connection.getCluster().hexists(key, field); } catch (Exception ex) { @@ -161,6 +189,9 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public Long hDel(byte[] key, byte[]... fields) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(fields, "Fields must not be null!"); + try { return connection.getCluster().hdel(key, fields); } catch (Exception ex) { @@ -175,6 +206,8 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public Long hLen(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().hlen(key); } catch (Exception ex) { @@ -189,6 +222,8 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public Set hKeys(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().hkeys(key); } catch (Exception ex) { @@ -203,6 +238,8 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public List hVals(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return new ArrayList<>(connection.getCluster().hvals(key)); } catch (Exception ex) { @@ -217,6 +254,8 @@ class JedisClusterHashCommands implements RedisHashCommands { @Override public Map hGetAll(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().hgetAll(key); } catch (Exception ex) { @@ -229,7 +268,9 @@ class JedisClusterHashCommands implements RedisHashCommands { * @see org.springframework.data.redis.connection.RedisHashCommands#hScan(byte[], org.springframework.data.redis.core.ScanOptions) */ @Override - public Cursor> hScan(final byte[] key, ScanOptions options) { + public Cursor> hScan(byte[] key, ScanOptions options) { + + Assert.notNull(key, "Key must not be null!"); return new ScanCursor>(options) { diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHyperLogLogCommands.java index 5bd982b71..403043392 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHyperLogLogCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterHyperLogLogCommands.java @@ -20,6 +20,7 @@ import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.connection.ClusterSlotHashUtil; import org.springframework.data.redis.connection.RedisHyperLogLogCommands; import org.springframework.data.redis.util.ByteUtils; +import org.springframework.util.Assert; /** * @author Christoph Strobl @@ -41,6 +42,9 @@ class JedisClusterHyperLogLogCommands implements RedisHyperLogLogCommands { @Override public Long pfAdd(byte[] key, byte[]... values) { + Assert.notEmpty(values, "PFADD requires at least one non 'null' value."); + Assert.noNullElements(values, "Values for PFADD must not contain 'null'."); + try { return connection.getCluster().pfadd(key, values); } catch (Exception ex) { @@ -55,6 +59,9 @@ class JedisClusterHyperLogLogCommands implements RedisHyperLogLogCommands { @Override public Long pfCount(byte[]... keys) { + Assert.notEmpty(keys, "PFCOUNT requires at least one non 'null' key."); + Assert.noNullElements(keys, "Keys for PFCOUNT must not contain 'null'."); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { try { @@ -74,6 +81,10 @@ class JedisClusterHyperLogLogCommands implements RedisHyperLogLogCommands { @Override public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { + Assert.notNull(destinationKey, "Destination key must not be null"); + Assert.notNull(sourceKeys, "Source keys must not be null"); + Assert.noNullElements(sourceKeys, "Keys for PFMERGE must not contain 'null'."); + byte[][] allKeys = ByteUtils.mergeArrays(destinationKey, sourceKeys); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java index 850995ffd..808e4d149 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterKeyCommands.java @@ -83,6 +83,8 @@ class JedisClusterKeyCommands implements RedisKeyCommands { @Override public DataType type(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return JedisConverters.toDataType(connection.getCluster().type(key)); } catch (Exception ex) { @@ -95,7 +97,7 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#keys(byte[]) */ @Override - public Set keys(final byte[] pattern) { + public Set keys(byte[] pattern) { Assert.notNull(pattern, "Pattern must not be null!"); @@ -114,8 +116,9 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisClusterConnection#keys(org.springframework.data.redis.connection.RedisClusterNode, byte[]) */ - public Set keys(RedisClusterNode node, final byte[] pattern) { + public Set keys(RedisClusterNode node, byte[] pattern) { + Assert.notNull(node, "RedisClusterNode must not be null!"); Assert.notNull(pattern, "Pattern must not be null!"); return connection.getClusterCommandExecutor() @@ -167,6 +170,8 @@ class JedisClusterKeyCommands implements RedisKeyCommands { */ public byte[] randomKey(RedisClusterNode node) { + Assert.notNull(node, "RedisClusterNode must not be null!"); + return connection.getClusterCommandExecutor() .executeCommandOnSingleNode((JedisClusterCommandCallback) client -> client.randomBinaryKey(), node) .getValue(); @@ -177,7 +182,10 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#rename(byte[], byte[]) */ @Override - public void rename(final byte[] sourceKey, final byte[] targetKey) { + public void rename(byte[] sourceKey, byte[] targetKey) { + + Assert.notNull(sourceKey, "Source key must not be null!"); + Assert.notNull(targetKey, "Target key must not be null!"); if (ClusterSlotHashUtil.isSameSlotForAllKeys(sourceKey, targetKey)) { @@ -203,7 +211,10 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#renameNX(byte[], byte[]) */ @Override - public Boolean renameNX(final byte[] sourceKey, final byte[] targetKey) { + public Boolean renameNX(byte[] sourceKey, byte[] targetKey) { + + Assert.notNull(sourceKey, "Source key must not be null!"); + Assert.notNull(targetKey, "Target key must not be null!"); if (ClusterSlotHashUtil.isSameSlotForAllKeys(sourceKey, targetKey)) { @@ -232,6 +243,8 @@ class JedisClusterKeyCommands implements RedisKeyCommands { @Override public Boolean expire(byte[] key, long seconds) { + Assert.notNull(key, "Key must not be null!"); + if (seconds > Integer.MAX_VALUE) { throw new UnsupportedOperationException("Jedis does not support seconds exceeding Integer.MAX_VALUE."); } @@ -247,7 +260,9 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpire(byte[], long) */ @Override - public Boolean pExpire(final byte[] key, final long millis) { + public Boolean pExpire(byte[] key, long millis) { + + Assert.notNull(key, "Key must not be null!"); try { return JedisConverters.toBoolean(connection.getCluster().pexpire(key, millis)); @@ -263,6 +278,8 @@ class JedisClusterKeyCommands implements RedisKeyCommands { @Override public Boolean expireAt(byte[] key, long unixTime) { + Assert.notNull(key, "Key must not be null!"); + try { return JedisConverters.toBoolean(connection.getCluster().expireAt(key, unixTime)); } catch (Exception ex) { @@ -277,6 +294,8 @@ class JedisClusterKeyCommands implements RedisKeyCommands { @Override public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { + Assert.notNull(key, "Key must not be null!"); + try { return JedisConverters.toBoolean(connection.getCluster().pexpireAt(key, unixTimeInMillis)); } catch (Exception ex) { @@ -291,6 +310,8 @@ class JedisClusterKeyCommands implements RedisKeyCommands { @Override public Boolean persist(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return JedisConverters.toBoolean(connection.getCluster().persist(key)); } catch (Exception ex) { @@ -314,6 +335,8 @@ class JedisClusterKeyCommands implements RedisKeyCommands { @Override public Long ttl(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().ttl(key); } catch (Exception ex) { @@ -328,6 +351,8 @@ class JedisClusterKeyCommands implements RedisKeyCommands { @Override public Long ttl(byte[] key, TimeUnit timeUnit) { + Assert.notNull(key, "Key must not be null!"); + try { return Converters.secondsToTimeUnit(connection.getCluster().ttl(key), timeUnit); } catch (Exception ex) { @@ -340,7 +365,9 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[]) */ @Override - public Long pTtl(final byte[] key) { + public Long pTtl(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); return connection.getClusterCommandExecutor() .executeCommandOnSingleNode((JedisClusterCommandCallback) client -> client.pttl(key), @@ -353,7 +380,9 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[], java.util.concurrent.TimeUnit) */ @Override - public Long pTtl(final byte[] key, final TimeUnit timeUnit) { + public Long pTtl(byte[] key, TimeUnit timeUnit) { + + Assert.notNull(key, "Key must not be null!"); return connection.getClusterCommandExecutor() .executeCommandOnSingleNode( @@ -367,7 +396,9 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#dump(byte[]) */ @Override - public byte[] dump(final byte[] key) { + public byte[] dump(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); return connection.getClusterCommandExecutor() .executeCommandOnSingleNode((JedisClusterCommandCallback) client -> client.dump(key), @@ -380,7 +411,10 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#restore(byte[], long, byte[]) */ @Override - public void restore(final byte[] key, final long ttlInMillis, final byte[] serializedValue) { + public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(serializedValue, "Serialized value must not be null!"); if (ttlInMillis > Integer.MAX_VALUE) { throw new UnsupportedOperationException("Jedis does not support ttlInMillis exceeding Integer.MAX_VALUE."); @@ -392,12 +426,14 @@ class JedisClusterKeyCommands implements RedisKeyCommands { } /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters) - */ + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters) + */ @Override public List sort(byte[] key, SortParameters params) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().sort(key, JedisConverters.toSortingParams(params)); } catch (Exception ex) { @@ -412,6 +448,8 @@ class JedisClusterKeyCommands implements RedisKeyCommands { @Override public Long sort(byte[] key, SortParameters params, byte[] storeKey) { + Assert.notNull(key, "Key must not be null!"); + List sorted = sort(key, params); if (!CollectionUtils.isEmpty(sorted)) { @@ -436,7 +474,9 @@ class JedisClusterKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#exists(byte[]) */ @Override - public Boolean exists(final byte[] key) { + public Boolean exists(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); try { return connection.getCluster().exists(key); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterListCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterListCommands.java index ed4f60856..a17c4681d 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterListCommands.java @@ -23,6 +23,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.ClusterSlotHashUtil; import org.springframework.data.redis.connection.RedisListCommands; import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisMultiKeyClusterCommandCallback; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; /** @@ -45,6 +46,8 @@ class JedisClusterListCommands implements RedisListCommands { @Override public Long rPush(byte[] key, byte[]... values) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().rpush(key, values); } catch (Exception ex) { @@ -59,6 +62,10 @@ class JedisClusterListCommands implements RedisListCommands { @Override public Long lPush(byte[] key, byte[]... values) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + try { return connection.getCluster().lpush(key, values); } catch (Exception ex) { @@ -73,6 +80,9 @@ class JedisClusterListCommands implements RedisListCommands { @Override public Long rPushX(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().rpushx(key, value); } catch (Exception ex) { @@ -87,6 +97,9 @@ class JedisClusterListCommands implements RedisListCommands { @Override public Long lPushX(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().lpushx(key, value); } catch (Exception ex) { @@ -101,6 +114,8 @@ class JedisClusterListCommands implements RedisListCommands { @Override public Long lLen(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().llen(key); } catch (Exception ex) { @@ -113,10 +128,12 @@ class JedisClusterListCommands implements RedisListCommands { * @see org.springframework.data.redis.connection.RedisListCommands#lRange(byte[], long, long) */ @Override - public List lRange(byte[] key, long begin, long end) { + public List lRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().lrange(key, begin, end); + return connection.getCluster().lrange(key, start, end); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -127,10 +144,12 @@ class JedisClusterListCommands implements RedisListCommands { * @see org.springframework.data.redis.connection.RedisListCommands#lTrim(byte[], long, long) */ @Override - public void lTrim(final byte[] key, final long begin, final long end) { + public void lTrim(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { - connection.getCluster().ltrim(key, begin, end); + connection.getCluster().ltrim(key, start, end); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -143,6 +162,8 @@ class JedisClusterListCommands implements RedisListCommands { @Override public byte[] lIndex(byte[] key, long index) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().lindex(key, index); } catch (Exception ex) { @@ -157,6 +178,8 @@ class JedisClusterListCommands implements RedisListCommands { @Override public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().linsert(key, JedisConverters.toListPosition(where), pivot, value); } catch (Exception ex) { @@ -171,6 +194,9 @@ class JedisClusterListCommands implements RedisListCommands { @Override public void lSet(byte[] key, long index, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { connection.getCluster().lset(key, index, value); } catch (Exception ex) { @@ -185,6 +211,9 @@ class JedisClusterListCommands implements RedisListCommands { @Override public Long lRem(byte[] key, long count, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().lrem(key, count, value); } catch (Exception ex) { @@ -199,6 +228,8 @@ class JedisClusterListCommands implements RedisListCommands { @Override public byte[] lPop(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().lpop(key); } catch (Exception ex) { @@ -213,6 +244,8 @@ class JedisClusterListCommands implements RedisListCommands { @Override public byte[] rPop(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().rpop(key); } catch (Exception ex) { @@ -225,7 +258,10 @@ class JedisClusterListCommands implements RedisListCommands { * @see org.springframework.data.redis.connection.RedisListCommands#bLPop(int, byte[][]) */ @Override - public List bLPop(final int timeout, final byte[]... keys) { + public List bLPop(int timeout, byte[]... keys) { + + Assert.notNull(keys, "Key must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { try { @@ -247,7 +283,10 @@ class JedisClusterListCommands implements RedisListCommands { * @see org.springframework.data.redis.connection.RedisListCommands#bRPop(int, byte[][]) */ @Override - public List bRPop(final int timeout, byte[]... keys) { + public List bRPop(int timeout, byte[]... keys) { + + Assert.notNull(keys, "Key must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); return connection.getClusterCommandExecutor() .executeMultiKeyCommand( @@ -263,6 +302,9 @@ class JedisClusterListCommands implements RedisListCommands { @Override public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(dstKey, "Destination key must not be null!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { try { return connection.getCluster().rpoplpush(srcKey, dstKey); @@ -283,6 +325,9 @@ class JedisClusterListCommands implements RedisListCommands { @Override public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(dstKey, "Destination key must not be null!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { try { return connection.getCluster().brpoplpush(srcKey, dstKey, timeout); 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 b17f2f988..e062194c6 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterServerCommands.java @@ -15,7 +15,6 @@ */ package org.springframework.data.redis.connection.jedis; -import org.springframework.lang.Nullable; import redis.clients.jedis.BinaryJedis; import java.util.ArrayList; @@ -34,6 +33,7 @@ import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisClusterCommandCallback; import org.springframework.data.redis.core.types.RedisClientInfo; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -234,7 +234,9 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#info(java.lang.String) */ @Override - public Properties info(final String section) { + public Properties info(String section) { + + Assert.notNull(section, "Section must not be null!"); Properties infos = new Properties(); @@ -257,7 +259,9 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { * @see org.springframework.data.redis.connection.RedisClusterServerCommands#info(org.springframework.data.redis.connection.RedisClusterNode, java.lang.String) */ @Override - public Properties info(RedisClusterNode node, final String section) { + public Properties info(RedisClusterNode node, String section) { + + Assert.notNull(section, "Section must not be null!"); return JedisConverters.toProperties(executeCommandOnSingleNode(client -> client.info(section), node).getValue()); } @@ -301,7 +305,9 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#getConfig(java.lang.String) */ @Override - public Properties getConfig(final String pattern) { + public Properties getConfig(String pattern) { + + Assert.notNull(pattern, "Pattern must not be null!"); List>> mapResult = connection.getClusterCommandExecutor() .executeCommandOnAllNodes((JedisClusterCommandCallback>) client -> client.configGet(pattern)) @@ -325,7 +331,9 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { * @see org.springframework.data.redis.connection.RedisClusterServerCommands#getConfig(org.springframework.data.redis.connection.RedisClusterNode, java.lang.String) */ @Override - public Properties getConfig(RedisClusterNode node, final String pattern) { + public Properties getConfig(RedisClusterNode node, String pattern) { + + Assert.notNull(pattern, "Pattern must not be null!"); return connection.getClusterCommandExecutor().executeCommandOnSingleNode( (JedisClusterCommandCallback) client -> Converters.toProperties(client.configGet(pattern)), node) @@ -337,7 +345,10 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#setConfig(java.lang.String, java.lang.String) */ @Override - public void setConfig(final String param, final String value) { + public void setConfig(String param, String value) { + + Assert.notNull(param, "Parameter must not be null!"); + Assert.notNull(value, "Value must not be null!"); connection.getClusterCommandExecutor() .executeCommandOnAllNodes((JedisClusterCommandCallback) client -> client.configSet(param, value)); @@ -348,7 +359,10 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { * @see org.springframework.data.redis.connection.RedisClusterServerCommands#setConfig(org.springframework.data.redis.connection.RedisClusterNode, java.lang.String, java.lang.String) */ @Override - public void setConfig(RedisClusterNode node, final String param, final String value) { + public void setConfig(RedisClusterNode node, String param, String value) { + + Assert.notNull(param, "Parameter must not be null!"); + Assert.notNull(value, "Value must not be null!"); executeCommandOnSingleNode(client -> client.configSet(param, value), node); } @@ -401,7 +415,8 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { @Override public void killClient(String host, int port) { - final String hostAndPort = String.format("%s:%s", host, port); + Assert.hasText(host, "Host for 'CLIENT KILL' must not be 'null' or 'empty'."); + String hostAndPort = String.format("%s:%s", host, port); connection.getClusterCommandExecutor() .executeCommandOnAllNodes((JedisClusterCommandCallback) client -> client.clientKill(hostAndPort)); @@ -488,9 +503,11 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { */ @Override public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, - final long timeout) { + long timeout) { - final int timeoutToUse = timeout <= Integer.MAX_VALUE ? (int) timeout : Integer.MAX_VALUE; + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(target, "Target node must not be null!"); + int timeoutToUse = timeout <= Integer.MAX_VALUE ? (int) timeout : Integer.MAX_VALUE; RedisClusterNode node = connection.getTopologyProvider().getTopology().lookup(target.getHost(), target.getPort()); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java index 1ee8cdef6..6c3823e18 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterSetCommands.java @@ -34,6 +34,7 @@ import org.springframework.data.redis.core.ScanCursor; import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.util.ByteUtils; +import org.springframework.util.Assert; /** * @author Christoph Strobl @@ -55,6 +56,10 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Long sAdd(byte[] key, byte[]... values) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + try { return connection.getCluster().sadd(key, values); } catch (Exception ex) { @@ -69,6 +74,10 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Long sRem(byte[] key, byte[]... values) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + try { return connection.getCluster().srem(key, values); } catch (Exception ex) { @@ -82,6 +91,9 @@ class JedisClusterSetCommands implements RedisSetCommands { */ @Override public byte[] sPop(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().spop(key); } catch (Exception ex) { @@ -96,6 +108,8 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public List sPop(byte[] key, long count) { + Assert.notNull(key, "Key must not be null!"); + try { return new ArrayList<>(connection.getCluster().spop(key, count)); } catch (Exception ex) { @@ -110,6 +124,10 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, destKey)) { try { return JedisConverters.toBoolean(connection.getCluster().smove(srcKey, destKey, value)); @@ -133,6 +151,8 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Long sCard(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().scard(key); } catch (Exception ex) { @@ -147,6 +167,9 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Boolean sIsMember(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().sismember(key, value); } catch (Exception ex) { @@ -161,6 +184,9 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Set sInter(byte[]... keys) { + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { try { return connection.getCluster().sinter(keys); @@ -204,6 +230,10 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Long sInterStore(byte[] destKey, byte[]... keys) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -228,6 +258,9 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Set sUnion(byte[]... keys) { + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { try { return connection.getCluster().sunion(keys); @@ -261,6 +294,10 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Long sUnionStore(byte[] destKey, byte[]... keys) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -285,6 +322,9 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Set sDiff(byte[]... keys) { + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { try { return connection.getCluster().sdiff(keys); @@ -321,6 +361,10 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Long sDiffStore(byte[] destKey, byte[]... keys) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -346,6 +390,8 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public Set sMembers(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().smembers(key); } catch (Exception ex) { @@ -360,6 +406,8 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public byte[] sRandMember(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().srandmember(key); } catch (Exception ex) { @@ -374,6 +422,8 @@ class JedisClusterSetCommands implements RedisSetCommands { @Override public List sRandMember(byte[] key, long count) { + Assert.notNull(key, "Key must not be null!"); + if (count > Integer.MAX_VALUE) { throw new IllegalArgumentException("Count cannot exceed Integer.MAX_VALUE!"); } @@ -390,7 +440,9 @@ class JedisClusterSetCommands implements RedisSetCommands { * @see org.springframework.data.redis.connection.RedisSetCommands#sScan(byte[], org.springframework.data.redis.core.ScanOptions) */ @Override - public Cursor sScan(final byte[] key, ScanOptions options) { + public Cursor sScan(byte[] key, ScanOptions options) { + + Assert.notNull(key, "Key must not be null!"); return new ScanCursor(options) { diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java index 172e6ad52..6692fdebf 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClusterStringCommands.java @@ -51,6 +51,8 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public byte[] get(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().get(key); } catch (Exception ex) { @@ -65,6 +67,9 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public byte[] getSet(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().getSet(key, value); } catch (Exception ex) { @@ -79,6 +84,7 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public List mGet(byte[]... keys) { + Assert.notNull(keys, "Keys must not be null!"); Assert.noNullElements(keys, "Keys must not contain null elements!"); if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { @@ -98,6 +104,9 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public void set(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { connection.getCluster().set(key, value); } catch (Exception ex) { @@ -112,6 +121,11 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + Assert.notNull(expiration, "Expiration must not be null!"); + Assert.notNull(option, "Option must not be null!"); + if (expiration == null || expiration.isPersistent()) { if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { @@ -155,6 +169,9 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Boolean setNX(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return JedisConverters.toBoolean(connection.getCluster().setnx(key, value)); } catch (Exception ex) { @@ -169,6 +186,9 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public void setEx(byte[] key, long seconds, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + if (seconds > Integer.MAX_VALUE) { throw new IllegalArgumentException("Seconds have cannot exceed Integer.MAX_VALUE!"); } @@ -185,11 +205,10 @@ class JedisClusterStringCommands implements RedisStringCommands { * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[]) */ @Override - public void pSetEx(final byte[] key, final long milliseconds, final byte[] value) { + public void pSetEx(byte[] key, long milliseconds, byte[] value) { - if (milliseconds > Integer.MAX_VALUE) { - throw new IllegalArgumentException("Milliseconds have cannot exceed Integer.MAX_VALUE!"); - } + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); connection.getClusterCommandExecutor().executeCommandOnSingleNode( (JedisClusterCommandCallback) client -> client.psetex(key, milliseconds, value), @@ -226,7 +245,7 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Boolean mSetNX(Map tuples) { - Assert.notNull(tuples, "Tuple must not be null!"); + Assert.notNull(tuples, "Tuples must not be null!"); if (ClusterSlotHashUtil.isSameSlotForAllKeys(tuples.keySet().toArray(new byte[tuples.keySet().size()][]))) { try { @@ -252,6 +271,8 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Long incr(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().incr(key); } catch (Exception ex) { @@ -266,6 +287,8 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Long incrBy(byte[] key, long value) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().incrBy(key, value); } catch (Exception ex) { @@ -280,6 +303,8 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Double incrBy(byte[] key, double value) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().incrByFloat(key, value); } catch (Exception ex) { @@ -294,6 +319,8 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Long decr(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().decr(key); } catch (Exception ex) { @@ -308,6 +335,8 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Long decrBy(byte[] key, long value) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().decrBy(key, value); } catch (Exception ex) { @@ -322,6 +351,9 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Long append(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().append(key, value); } catch (Exception ex) { @@ -334,10 +366,12 @@ class JedisClusterStringCommands implements RedisStringCommands { * @see org.springframework.data.redis.connection.RedisStringCommands#getRange(byte[], long, long) */ @Override - public byte[] getRange(byte[] key, long begin, long end) { + public byte[] getRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().getrange(key, begin, end); + return connection.getCluster().getrange(key, start, end); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -350,6 +384,9 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public void setRange(byte[] key, byte[] value, long offset) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { connection.getCluster().setrange(key, offset, value); } catch (Exception ex) { @@ -364,6 +401,8 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Boolean getBit(byte[] key, long offset) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().getbit(key, offset); } catch (Exception ex) { @@ -378,6 +417,8 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Boolean setBit(byte[] key, long offset, boolean value) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().setbit(key, offset, value); } catch (Exception ex) { @@ -392,6 +433,8 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Long bitCount(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().bitcount(key); } catch (Exception ex) { @@ -404,10 +447,12 @@ class JedisClusterStringCommands implements RedisStringCommands { * @see org.springframework.data.redis.connection.RedisStringCommands#bitCount(byte[], long, long) */ @Override - public Long bitCount(byte[] key, long begin, long end) { + public Long bitCount(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().bitcount(key, begin, end); + return connection.getCluster().bitcount(key, start, end); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -420,6 +465,9 @@ class JedisClusterStringCommands implements RedisStringCommands { @Override public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + Assert.notNull(op, "BitOperation must not be null!"); + Assert.notNull(destination, "Destination key must not be null!"); + byte[][] allKeys = ByteUtils.mergeArrays(destination, keys); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -439,6 +487,7 @@ class JedisClusterStringCommands implements RedisStringCommands { */ @Override public Long strLen(byte[] key) { + Assert.notNull(key, "Key must not be null!"); try { return connection.getCluster().strlen(key); 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 6e4db6027..31b2779a6 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 @@ -52,6 +52,9 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Boolean zAdd(byte[] key, double score, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return JedisConverters.toBoolean(connection.getCluster().zadd(key, score, value)); } catch (Exception ex) { @@ -66,6 +69,9 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zAdd(byte[] key, Set tuples) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(tuples, "Tuples must not be null!"); + try { return connection.getCluster().zadd(key, JedisConverters.toTupleMap(tuples)); } catch (Exception ex) { @@ -80,6 +86,10 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zRem(byte[] key, byte[]... values) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + try { return connection.getCluster().zrem(key, values); } catch (Exception ex) { @@ -94,6 +104,10 @@ class JedisClusterZSetCommands implements RedisZSetCommands { */ @Override public Double zIncrBy(byte[] key, double increment, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().zincrby(key, increment, value); } catch (Exception ex) { @@ -108,6 +122,9 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zRank(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().zrank(key, value); } catch (Exception ex) { @@ -122,6 +139,9 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zRevRank(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().zrevrank(key, value); } catch (Exception ex) { @@ -134,10 +154,12 @@ class JedisClusterZSetCommands implements RedisZSetCommands { * @see org.springframework.data.redis.connection.RedisZSetCommands#zRange(byte[], long, long) */ @Override - public Set zRange(byte[] key, long begin, long end) { + public Set zRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().zrange(key, begin, end); + return connection.getCluster().zrange(key, start, end); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -150,6 +172,7 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZRANGEBYSCOREWITHSCORES."); byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); @@ -173,7 +196,9 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCORE."); + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); @@ -194,6 +219,7 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCOREWITHSCORES."); byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); @@ -217,6 +243,7 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zCount(byte[] key, Range range) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZCOUNT."); byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); @@ -236,6 +263,7 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zRemRangeByScore(byte[] key, Range range) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZREMRANGEBYSCORE."); byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); @@ -256,6 +284,7 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScore(byte[] key, Range range, Limit limit) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZRANGEBYSCORE."); byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); @@ -278,6 +307,7 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRangeByLex(byte[] key, Range range, Limit limit) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); Assert.notNull(limit, "Limit must not be null!"); @@ -299,10 +329,12 @@ class JedisClusterZSetCommands implements RedisZSetCommands { * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeWithScores(byte[], long, long) */ @Override - public Set zRangeWithScores(byte[] key, long begin, long end) { + public Set zRangeWithScores(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { - return JedisConverters.toTupleSet(connection.getCluster().zrangeWithScores(key, begin, end)); + return JedisConverters.toTupleSet(connection.getCluster().zrangeWithScores(key, start, end)); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -315,6 +347,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScore(byte[] key, double min, double max) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().zrangeByScore(key, min, max); } catch (Exception ex) { @@ -329,6 +363,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScoreWithScores(byte[] key, double min, double max) { + Assert.notNull(key, "Key must not be null!"); + try { return JedisConverters.toTupleSet(connection.getCluster().zrangeByScoreWithScores(key, min, max)); } catch (Exception ex) { @@ -343,6 +379,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { + Assert.notNull(key, "Key must not be null!"); + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); } @@ -362,6 +400,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { + Assert.notNull(key, "Key must not be null!"); + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); } @@ -379,10 +419,12 @@ class JedisClusterZSetCommands implements RedisZSetCommands { * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRange(byte[], long, long) */ @Override - public Set zRevRange(byte[] key, long begin, long end) { + public Set zRevRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().zrevrange(key, begin, end); + return connection.getCluster().zrevrange(key, start, end); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -393,10 +435,12 @@ class JedisClusterZSetCommands implements RedisZSetCommands { * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeWithScores(byte[], long, long) */ @Override - public Set zRevRangeWithScores(byte[] key, long begin, long end) { + public Set zRevRangeWithScores(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { - return JedisConverters.toTupleSet(connection.getCluster().zrevrangeWithScores(key, begin, end)); + return JedisConverters.toTupleSet(connection.getCluster().zrevrangeWithScores(key, start, end)); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -409,6 +453,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRevRangeByScore(byte[] key, double min, double max) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().zrevrangeByScore(key, max, min); } catch (Exception ex) { @@ -423,6 +469,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { + Assert.notNull(key, "Key must not be null!"); + try { return JedisConverters.toTupleSet(connection.getCluster().zrevrangeByScoreWithScores(key, max, min)); } catch (Exception ex) { @@ -437,6 +485,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { + Assert.notNull(key, "Key must not be null!"); + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); } @@ -456,6 +506,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { + Assert.notNull(key, "Key must not be null!"); + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); } @@ -475,6 +527,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zCount(byte[] key, double min, double max) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().zcount(key, min, max); } catch (Exception ex) { @@ -489,6 +543,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zCard(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().zcard(key); } catch (Exception ex) { @@ -503,6 +559,9 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Double zScore(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { return connection.getCluster().zscore(key, value); } catch (Exception ex) { @@ -515,10 +574,12 @@ class JedisClusterZSetCommands implements RedisZSetCommands { * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRange(byte[], long, long) */ @Override - public Long zRemRange(byte[] key, long begin, long end) { + public Long zRemRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { - return connection.getCluster().zremrangeByRank(key, begin, end); + return connection.getCluster().zremrangeByRank(key, start, end); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -531,6 +592,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zRemRangeByScore(byte[] key, double min, double max) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().zremrangeByScore(key, min, max); } catch (Exception ex) { @@ -545,6 +608,10 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zUnionStore(byte[] destKey, byte[]... sets) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -566,6 +633,10 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -589,6 +660,10 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zInterStore(byte[] destKey, byte[]... sets) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -610,6 +685,10 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, sets); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -631,7 +710,10 @@ class JedisClusterZSetCommands implements RedisZSetCommands { * @see org.springframework.data.redis.connection.RedisZSetCommands#zScan(byte[], org.springframework.data.redis.core.ScanOptions) */ @Override - public Cursor zScan(final byte[] key, final ScanOptions options) { + public Cursor zScan(byte[] key, ScanOptions options) { + + Assert.notNull(key, "Key must not be null!"); + return new ScanCursor(options) { @Override @@ -654,6 +736,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScore(byte[] key, String min, String max) { + Assert.notNull(key, "Key must not be null!"); + try { return connection.getCluster().zrangeByScore(key, JedisConverters.toBytes(min), JedisConverters.toBytes(max)); } catch (Exception ex) { @@ -668,6 +752,8 @@ class JedisClusterZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { + Assert.notNull(key, "Key must not be null!"); + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { throw new IllegalArgumentException("Count/Offset cannot exceed Integer.MAX_VALUE!"); } 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 de5df8c40..0df670886 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 @@ -102,7 +102,7 @@ public class JedisConnection extends AbstractRedisConnection { private final Jedis jedis; private final Client client; private @Nullable Transaction transaction; - private final Pool pool; + private final @Nullable Pool pool; /** * flag indicating whether the connection needs to be dropped or not */ @@ -172,7 +172,7 @@ public class JedisConnection extends AbstractRedisConnection { * @param clientName the client name, can be {@literal null}. * @since 1.8 */ - protected JedisConnection(Jedis jedis, Pool pool, int dbIndex, String clientName) { + protected JedisConnection(Jedis jedis, @Nullable Pool pool, int dbIndex, String clientName) { // extract underlying connection for batch operations client = (Client) ReflectionUtils.getField(CLIENT_FIELD, jedis); @@ -469,7 +469,7 @@ public class JedisConnection extends AbstractRedisConnection { private List convertPipelineResults() { List results = new ArrayList<>(); - pipeline.sync(); + getRequiredPipeline().sync(); Exception cause = null; for (FutureResult> result : pipelinedResults) { try { @@ -516,11 +516,11 @@ public class JedisConnection extends AbstractRedisConnection { public byte[] echo(byte[] message) { try { if (isPipelined()) { - pipeline(new JedisResult(pipeline.echo(message))); + pipeline(new JedisResult(getRequiredPipeline().echo(message))); return null; } if (isQueueing()) { - transaction(new JedisResult(transaction.echo(message))); + transaction(new JedisResult(getRequiredTransaction().echo(message))); return null; } return jedis.echo(message); @@ -537,11 +537,11 @@ public class JedisConnection extends AbstractRedisConnection { public String ping() { try { if (isPipelined()) { - pipeline(new JedisResult(pipeline.ping())); + pipeline(new JedisResult(getRequiredPipeline().ping())); return null; } if (isQueueing()) { - transaction(new JedisResult(transaction.ping())); + transaction(new JedisResult(getRequiredTransaction().ping())); return null; } return jedis.ping(); @@ -558,10 +558,10 @@ public class JedisConnection extends AbstractRedisConnection { public void discard() { try { if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.discard())); + pipeline(new JedisStatusResult(getRequiredPipeline().discard())); return; } - transaction.discard(); + getRequiredTransaction().discard(); } catch (Exception ex) { throw convertJedisAccessException(ex); } finally { @@ -578,7 +578,7 @@ public class JedisConnection extends AbstractRedisConnection { public List exec() { try { if (isPipelined()) { - pipeline(new JedisResult(pipeline.exec(), + pipeline(new JedisResult(getRequiredPipeline().exec(), new TransactionResultConverter<>(new LinkedList<>(txResults), JedisConverters.exceptionConverter()))); return null; } @@ -603,11 +603,33 @@ public class JedisConnection extends AbstractRedisConnection { return pipeline; } + public Pipeline getRequiredPipeline() { + + Pipeline pipeline = getPipeline(); + + if (pipeline == null) { + throw new IllegalStateException("Connection has no active pipeline"); + } + + return pipeline; + } + @Nullable public Transaction getTransaction() { return transaction; } + public Transaction getRequiredTransaction() { + + Transaction transaction = getTransaction(); + + if (transaction == null) { + throw new IllegalStateException("Connection has no active transaction"); + } + + return transaction; + } + public Jedis getJedis() { return jedis; } @@ -635,7 +657,7 @@ public class JedisConnection extends AbstractRedisConnection { } try { if (isPipelined()) { - pipeline.multi(); + getRequiredPipeline().multi(); return; } this.transaction = jedis.multi(); @@ -652,11 +674,11 @@ public class JedisConnection extends AbstractRedisConnection { public void select(int dbIndex) { try { if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.select(dbIndex))); + pipeline(new JedisStatusResult(getRequiredPipeline().select(dbIndex))); return; } if (isQueueing()) { - transaction(new JedisStatusResult(transaction.select(dbIndex))); + transaction(new JedisStatusResult(getRequiredTransaction().select(dbIndex))); return; } jedis.select(dbIndex); @@ -690,7 +712,7 @@ public class JedisConnection extends AbstractRedisConnection { try { for (byte[] key : keys) { if (isPipelined()) { - pipeline(new JedisStatusResult(pipeline.watch(key))); + pipeline(new JedisStatusResult(getRequiredPipeline().watch(key))); } else { jedis.watch(key); } @@ -712,11 +734,11 @@ public class JedisConnection extends AbstractRedisConnection { public Long publish(byte[] channel, byte[] message) { try { if (isPipelined()) { - pipeline(new JedisResult(pipeline.publish(channel, message))); + pipeline(new JedisResult(getRequiredPipeline().publish(channel, message))); return null; } if (isQueueing()) { - transaction(new JedisResult(transaction.publish(channel, message))); + transaction(new JedisResult(getRequiredTransaction().publish(channel, message))); return null; } return jedis.publish(channel, message); @@ -817,10 +839,6 @@ public class JedisConnection extends AbstractRedisConnection { @Override protected boolean isActive(RedisNode node) { - if (node == null) { - return false; - } - Jedis temp = null; try { temp = getJedis(node); 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 ee340a4da..7ae605382 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java @@ -15,7 +15,6 @@ */ package org.springframework.data.redis.connection.jedis; -import org.springframework.lang.Nullable; import redis.clients.jedis.Client; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; @@ -61,6 +60,7 @@ import org.springframework.data.redis.connection.RedisSentinelConfiguration; import org.springframework.data.redis.connection.RedisSentinelConnection; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.jedis.JedisClusterConnection.JedisClusterTopologyProvider; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -680,6 +680,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, * * @return the poolConfig */ + @Nullable public GenericObjectPoolConfig getPoolConfig() { return clientConfiguration.getPoolConfig().orElse(null); } @@ -736,6 +737,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, * @return the client name. * @since 1.8 */ + @Nullable public String getClientName() { return clientConfiguration.getClientName().orElse(null); } @@ -765,6 +767,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, * @return the {@link RedisStandaloneConfiguration}. * @since 2.0 */ + @Nullable public RedisStandaloneConfiguration getStandaloneConfiguration() { return standaloneConfig; } @@ -773,6 +776,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, * @return the {@link RedisStandaloneConfiguration}, may be {@literal null}. * @since 2.0 */ + @Nullable public RedisSentinelConfiguration getSentinelConfiguration() { return sentinelConfig; } @@ -781,6 +785,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, * @return the {@link RedisClusterConfiguration}, may be {@literal null}. * @since 2.0 */ + @Nullable public RedisClusterConfiguration getClusterConfiguration() { return clusterConfig; } 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 6a9899cfa..0598eeefc 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 @@ -67,6 +67,7 @@ import org.springframework.data.redis.connection.convert.StringToRedisClientInfo import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.core.types.RedisClientInfo; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -354,7 +355,9 @@ abstract public class JedisConverters extends Converters { return result; } - public static SortingParams toSortingParams(SortParameters params) { + @Nullable + public static SortingParams toSortingParams(@Nullable SortParameters params) { + SortingParams jedisParams = null; if (params != null) { jedisParams = new SortingParams(); @@ -406,7 +409,7 @@ abstract public class JedisConverters extends Converters { * @return * @since 1.6 */ - public static byte[] boundaryToBytesForZRange(Boundary boundary, byte[] defaultValue) { + public static byte[] boundaryToBytesForZRange(@Nullable Boundary boundary, byte[] defaultValue) { if (boundary == null || boundary.getValue() == null) { return defaultValue; @@ -422,7 +425,7 @@ abstract public class JedisConverters extends Converters { * @return * @since 1.6 */ - public static byte[] boundaryToBytesForZRangeByLex(Boundary boundary, byte[] defaultValue) { + public static byte[] boundaryToBytesForZRangeByLex(@Nullable Boundary boundary, byte[] defaultValue) { if (boundary == null || boundary.getValue() == null) { return defaultValue; diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java index 0fb03836f..ebbd826a6 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisGeoCommands.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import redis.clients.jedis.GeoCoordinate; import redis.clients.jedis.GeoUnit; @@ -38,13 +40,10 @@ import org.springframework.util.Assert; * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisGeoCommands implements RedisGeoCommands { - private final JedisConnection connection; - - JedisGeoCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; /* * (non-Javadoc) @@ -59,12 +58,14 @@ class JedisGeoCommands implements RedisGeoCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().geoadd(key, point.getX(), point.getY(), member))); + pipeline(connection + .newJedisResult(connection.getRequiredPipeline().geoadd(key, point.getX(), point.getY(), member))); return null; } if (isQueueing()) { transaction( - connection.newJedisResult(connection.getTransaction().geoadd(key, point.getX(), point.getY(), member))); + connection + .newJedisResult(connection.getRequiredTransaction().geoadd(key, point.getX(), point.getY(), member))); return null; } @@ -92,11 +93,11 @@ class JedisGeoCommands implements RedisGeoCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().geoadd(key, redisGeoCoordinateMap))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().geoadd(key, redisGeoCoordinateMap))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().geoadd(key, redisGeoCoordinateMap))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().geoadd(key, redisGeoCoordinateMap))); return null; } @@ -124,11 +125,11 @@ class JedisGeoCommands implements RedisGeoCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().geoadd(key, redisGeoCoordinateMap))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().geoadd(key, redisGeoCoordinateMap))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().geoadd(key, redisGeoCoordinateMap))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().geoadd(key, redisGeoCoordinateMap))); return null; } @@ -153,12 +154,14 @@ class JedisGeoCommands implements RedisGeoCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().geodist(key, member1, member2), distanceConverter)); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().geodist(key, member1, member2), + distanceConverter)); return null; } if (isQueueing()) { transaction( - connection.newJedisResult(connection.getTransaction().geodist(key, member1, member2), distanceConverter)); + connection.newJedisResult(connection.getRequiredTransaction().geodist(key, member1, member2), + distanceConverter)); return null; } @@ -185,12 +188,13 @@ class JedisGeoCommands implements RedisGeoCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().geodist(key, member1, member2, geoUnit), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().geodist(key, member1, member2, geoUnit), distanceConverter)); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().geodist(key, member1, member2, geoUnit), + transaction(connection.newJedisResult( + connection.getRequiredTransaction().geodist(key, member1, member2, geoUnit), distanceConverter)); return null; } @@ -214,12 +218,12 @@ class JedisGeoCommands implements RedisGeoCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().geohash(key, members), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().geohash(key, members), JedisConverters.bytesListToStringListConverter())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().geohash(key, members), + transaction(connection.newJedisResult(connection.getRequiredTransaction().geohash(key, members), JedisConverters.bytesListToStringListConverter())); return null; } @@ -244,11 +248,11 @@ class JedisGeoCommands implements RedisGeoCommands { ListConverter converter = JedisConverters.geoCoordinateToPointConverter(); try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().geopos(key, members), converter)); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().geopos(key, members), converter)); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().geopos(key, members), converter)); + transaction(connection.newJedisResult(connection.getRequiredTransaction().geopos(key, members), converter)); return null; } return converter.convert(connection.getJedis().geopos(key, members)); @@ -273,7 +277,7 @@ class JedisGeoCommands implements RedisGeoCommands { if (isPipelined()) { pipeline( connection.newJedisResult( - connection.getPipeline().georadius(key, within.getCenter().getX(), within.getCenter().getY(), + connection.getRequiredPipeline().georadius(key, within.getCenter().getX(), within.getCenter().getY(), within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric())), converter)); return null; @@ -281,7 +285,7 @@ class JedisGeoCommands implements RedisGeoCommands { if (isQueueing()) { transaction( connection.newJedisResult( - connection.getTransaction().georadius(key, within.getCenter().getX(), within.getCenter().getY(), + connection.getRequiredTransaction().georadius(key, within.getCenter().getX(), within.getCenter().getY(), within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric())), converter)); return null; @@ -312,13 +316,14 @@ class JedisGeoCommands implements RedisGeoCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().georadius(key, within.getCenter().getX(), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().georadius(key, within.getCenter().getX(), within.getCenter().getY(), within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()), geoRadiusParam), converter)); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().georadius(key, within.getCenter().getX(), + transaction(connection.newJedisResult(connection.getRequiredTransaction().georadius(key, + within.getCenter().getX(), within.getCenter().getY(), within.getRadius().getValue(), JedisConverters.toGeoUnit(within.getRadius().getMetric()), geoRadiusParam), converter)); return null; @@ -350,12 +355,12 @@ class JedisGeoCommands implements RedisGeoCommands { try { if (isPipelined()) { pipeline(connection.newJedisResult( - connection.getPipeline().georadiusByMember(key, member, radius.getValue(), geoUnit), converter)); + connection.getRequiredPipeline().georadiusByMember(key, member, radius.getValue(), geoUnit), converter)); return null; } if (isQueueing()) { transaction(connection.newJedisResult( - connection.getTransaction().georadiusByMember(key, member, radius.getValue(), geoUnit), converter)); + connection.getRequiredTransaction().georadiusByMember(key, member, radius.getValue(), geoUnit), converter)); return null; } @@ -386,13 +391,14 @@ class JedisGeoCommands implements RedisGeoCommands { try { if (isPipelined()) { pipeline(connection.newJedisResult( - connection.getPipeline().georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam), + connection.getRequiredPipeline().georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam), converter)); return null; } if (isQueueing()) { transaction(connection.newJedisResult( - connection.getTransaction().georadiusByMember(key, member, radius.getValue(), geoUnit, geoRadiusParam), + connection.getRequiredTransaction().georadiusByMember(key, member, radius.getValue(), geoUnit, + geoRadiusParam), converter)); return null; } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java index 0e702766c..2250b35b1 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHashCommands.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import redis.clients.jedis.ScanParams; import redis.clients.jedis.ScanResult; @@ -29,19 +31,17 @@ import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; /** * @author Christoph Strobl * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisHashCommands implements RedisHashCommands { - private final JedisConnection connection; - - JedisHashCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; /* * (non-Javadoc) @@ -50,14 +50,18 @@ class JedisHashCommands implements RedisHashCommands { @Override public Boolean hSet(byte[] key, byte[] field, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hset(key, field, value), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hset(key, field, value), JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hset(key, field, value), + transaction(connection.newJedisResult(connection.getRequiredTransaction().hset(key, field, value), JedisConverters.longToBoolean())); return null; } @@ -74,14 +78,18 @@ class JedisHashCommands implements RedisHashCommands { @Override public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hsetnx(key, field, value), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hsetnx(key, field, value), JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hsetnx(key, field, value), + transaction(connection.newJedisResult(connection.getRequiredTransaction().hsetnx(key, field, value), JedisConverters.longToBoolean())); return null; } @@ -98,13 +106,16 @@ class JedisHashCommands implements RedisHashCommands { @Override public Long hDel(byte[] key, byte[]... fields) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(fields, "Fields must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hdel(key, fields))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hdel(key, fields))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hdel(key, fields))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hdel(key, fields))); return null; } return connection.getJedis().hdel(key, fields); @@ -120,13 +131,16 @@ class JedisHashCommands implements RedisHashCommands { @Override public Boolean hExists(byte[] key, byte[] field) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Fields must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hexists(key, field))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hexists(key, field))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hexists(key, field))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hexists(key, field))); return null; } return connection.getJedis().hexists(key, field); @@ -142,13 +156,16 @@ class JedisHashCommands implements RedisHashCommands { @Override public byte[] hGet(byte[] key, byte[] field) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hget(key, field))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hget(key, field))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hget(key, field))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hget(key, field))); return null; } return connection.getJedis().hget(key, field); @@ -164,13 +181,15 @@ class JedisHashCommands implements RedisHashCommands { @Override public Map hGetAll(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hgetAll(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hgetAll(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hgetAll(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hgetAll(key))); return null; } return connection.getJedis().hgetAll(key); @@ -186,13 +205,16 @@ class JedisHashCommands implements RedisHashCommands { @Override public Long hIncrBy(byte[] key, byte[] field, long delta) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hincrBy(key, field, delta))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hincrBy(key, field, delta))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hincrBy(key, field, delta))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hincrBy(key, field, delta))); return null; } return connection.getJedis().hincrBy(key, field, delta); @@ -208,13 +230,16 @@ class JedisHashCommands implements RedisHashCommands { @Override public Double hIncrBy(byte[] key, byte[] field, double delta) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hincrByFloat(key, field, delta))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hincrByFloat(key, field, delta))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hincrByFloat(key, field, delta))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hincrByFloat(key, field, delta))); return null; } return connection.getJedis().hincrByFloat(key, field, delta); @@ -230,13 +255,15 @@ class JedisHashCommands implements RedisHashCommands { @Override public Set hKeys(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hkeys(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hkeys(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hkeys(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hkeys(key))); return null; } return connection.getJedis().hkeys(key); @@ -252,13 +279,15 @@ class JedisHashCommands implements RedisHashCommands { @Override public Long hLen(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hlen(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hlen(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hlen(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hlen(key))); return null; } return connection.getJedis().hlen(key); @@ -274,13 +303,16 @@ class JedisHashCommands implements RedisHashCommands { @Override public List hMGet(byte[] key, byte[]... fields) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(fields, "Fields must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hmget(key, fields))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hmget(key, fields))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hmget(key, fields))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hmget(key, fields))); return null; } return connection.getJedis().hmget(key, fields); @@ -294,18 +326,21 @@ class JedisHashCommands implements RedisHashCommands { * @see org.springframework.data.redis.connection.RedisHashCommands#hMSet(byte[], java.util.Map) */ @Override - public void hMSet(byte[] key, Map tuple) { + public void hMSet(byte[] key, Map hashes) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(hashes, "Hashes must not be null!"); try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().hmset(key, tuple))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().hmset(key, hashes))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().hmset(key, tuple))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().hmset(key, hashes))); return; } - connection.getJedis().hmset(key, tuple); + connection.getJedis().hmset(key, hashes); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -318,13 +353,15 @@ class JedisHashCommands implements RedisHashCommands { @Override public List hVals(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().hvals(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().hvals(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().hvals(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().hvals(key))); return null; } return connection.getJedis().hvals(key); @@ -351,6 +388,8 @@ class JedisHashCommands implements RedisHashCommands { */ public Cursor> hScan(byte[] key, long cursorId, ScanOptions options) { + Assert.notNull(key, "Key must not be null!"); + return new KeyBoundCursor>(key, cursorId, options) { @Override @@ -367,6 +406,7 @@ class JedisHashCommands implements RedisHashCommands { return new ScanIteration<>(Long.valueOf(result.getStringCursor()), result.getResult()); } + @Override protected void doClose() { JedisHashCommands.this.connection.close(); }; diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java index a1c0b2f11..028c6d81a 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisHyperLogLogCommands.java @@ -15,6 +15,9 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + import org.springframework.data.redis.connection.RedisHyperLogLogCommands; import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; import org.springframework.util.Assert; @@ -24,13 +27,10 @@ import org.springframework.util.Assert; * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisHyperLogLogCommands implements RedisHyperLogLogCommands { - private final JedisConnection connection; - - JedisHyperLogLogCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; /* * (non-Javadoc) @@ -44,11 +44,11 @@ class JedisHyperLogLogCommands implements RedisHyperLogLogCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().pfadd(key, values))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().pfadd(key, values))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().pfadd(key, values))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().pfadd(key, values))); return null; } return connection.getJedis().pfadd(key, values); @@ -65,15 +65,15 @@ class JedisHyperLogLogCommands implements RedisHyperLogLogCommands { public Long pfCount(byte[]... keys) { Assert.notEmpty(keys, "PFCOUNT requires at least one non 'null' key."); - Assert.noNullElements(keys, "Keys for PFOUNT must not contain 'null'."); + Assert.noNullElements(keys, "Keys for PFCOUNT must not contain 'null'."); try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().pfcount(keys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().pfcount(keys))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().pfcount(keys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().pfcount(keys))); return null; } return connection.getJedis().pfcount(keys); @@ -89,13 +89,17 @@ class JedisHyperLogLogCommands implements RedisHyperLogLogCommands { @Override public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { + Assert.notNull(destinationKey, "Destination key must not be null"); + Assert.notNull(sourceKeys, "Source keys must not be null"); + Assert.noNullElements(sourceKeys, "Keys for PFMERGE must not contain 'null'."); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().pfmerge(destinationKey, sourceKeys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().pfmerge(destinationKey, sourceKeys))); return; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().pfmerge(destinationKey, sourceKeys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().pfmerge(destinationKey, sourceKeys))); return; } connection.getJedis().pfmerge(destinationKey, sourceKeys); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java index 27dcdbd9c..18ccb8b77 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisKeyCommands.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import redis.clients.jedis.ScanParams; import redis.clients.jedis.SortingParams; @@ -31,6 +33,7 @@ import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanCursor; import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -38,13 +41,10 @@ import org.springframework.util.Assert; * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisKeyCommands implements RedisKeyCommands { - private final JedisConnection connection; - - JedisKeyCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; /* * (non-Javadoc) @@ -53,13 +53,15 @@ class JedisKeyCommands implements RedisKeyCommands { @Override public Boolean exists(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().exists(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().exists(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().exists(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().exists(key))); return null; } return connection.getJedis().exists(key); @@ -75,13 +77,16 @@ class JedisKeyCommands implements RedisKeyCommands { @Override public Long del(byte[]... keys) { + Assert.noNullElements(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().del(keys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().del(keys))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().del(keys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().del(keys))); return null; } return connection.getJedis().del(keys); @@ -97,14 +102,17 @@ class JedisKeyCommands implements RedisKeyCommands { @Override public DataType type(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().type(key), JedisConverters.stringToDataType())); + pipeline( + connection.newJedisResult(connection.getRequiredPipeline().type(key), JedisConverters.stringToDataType())); return null; } if (isQueueing()) { - transaction( - connection.newJedisResult(connection.getTransaction().type(key), JedisConverters.stringToDataType())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().type(key), + JedisConverters.stringToDataType())); return null; } return JedisConverters.toDataType(connection.getJedis().type(key)); @@ -120,13 +128,15 @@ class JedisKeyCommands implements RedisKeyCommands { @Override public Set keys(byte[] pattern) { + Assert.notNull(pattern, "Pattern must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().keys(pattern))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().keys(pattern))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().keys(pattern))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().keys(pattern))); return null; } return connection.getJedis().keys(pattern); @@ -139,6 +149,7 @@ class JedisKeyCommands implements RedisKeyCommands { * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisKeyCommands#scan(org.springframework.data.redis.core.ScanOptions) */ + @Override public Cursor scan(ScanOptions options) { return scan(0, options != null ? options : ScanOptions.NONE); } @@ -182,11 +193,11 @@ class JedisKeyCommands implements RedisKeyCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().randomKeyBinary())); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().randomKeyBinary())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().randomKeyBinary())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().randomKeyBinary())); return null; } return connection.getJedis().randomBinaryKey(); @@ -200,18 +211,21 @@ class JedisKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#rename(byte[], byte[]) */ @Override - public void rename(byte[] oldName, byte[] newName) { + public void rename(byte[] sourceKey, byte[] targetKey) { + + Assert.notNull(sourceKey, "Source key must not be null!"); + Assert.notNull(targetKey, "Target key must not be null!"); try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().rename(oldName, newName))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().rename(sourceKey, targetKey))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().rename(oldName, newName))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().rename(sourceKey, targetKey))); return; } - connection.getJedis().rename(oldName, newName); + connection.getJedis().rename(sourceKey, targetKey); } catch (Exception ex) { throw connection.convertJedisAccessException(ex); } @@ -222,20 +236,23 @@ class JedisKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#renameNX(byte[], byte[]) */ @Override - public Boolean renameNX(byte[] oldName, byte[] newName) { + public Boolean renameNX(byte[] sourceKey, byte[] targetKey) { + + Assert.notNull(sourceKey, "Source key must not be null!"); + Assert.notNull(targetKey, "Target key must not be null!"); try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().renamenx(oldName, newName), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().renamenx(sourceKey, targetKey), JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().renamenx(oldName, newName), + transaction(connection.newJedisResult(connection.getRequiredTransaction().renamenx(sourceKey, targetKey), JedisConverters.longToBoolean())); return null; } - return JedisConverters.toBoolean(connection.getJedis().renamenx(oldName, newName)); + return JedisConverters.toBoolean(connection.getJedis().renamenx(sourceKey, targetKey)); } catch (Exception ex) { throw connection.convertJedisAccessException(ex); } @@ -256,12 +273,12 @@ class JedisKeyCommands implements RedisKeyCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().expire(key, (int) seconds), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().expire(key, (int) seconds), JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().expire(key, (int) seconds), + transaction(connection.newJedisResult(connection.getRequiredTransaction().expire(key, (int) seconds), JedisConverters.longToBoolean())); return null; } @@ -271,32 +288,6 @@ class JedisKeyCommands implements RedisKeyCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#expireAt(byte[], long) - */ - @Override - public Boolean expireAt(byte[] key, long unixTime) { - - Assert.notNull(key, "Key must not be null!"); - - try { - if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().expireAt(key, unixTime), - JedisConverters.longToBoolean())); - return null; - } - if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().expireAt(key, unixTime), - JedisConverters.longToBoolean())); - return null; - } - return JedisConverters.toBoolean(connection.getJedis().expireAt(key, unixTime)); - } catch (Exception ex) { - throw connection.convertJedisAccessException(ex); - } - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpire(byte[], long) @@ -308,12 +299,12 @@ class JedisKeyCommands implements RedisKeyCommands { try { if (isPipelined()) { - pipeline( - connection.newJedisResult(connection.getPipeline().pexpire(key, millis), JedisConverters.longToBoolean())); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().pexpire(key, millis), + JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().pexpire(key, millis), + transaction(connection.newJedisResult(connection.getRequiredTransaction().pexpire(key, millis), JedisConverters.longToBoolean())); return null; } @@ -323,6 +314,32 @@ class JedisKeyCommands implements RedisKeyCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#expireAt(byte[], long) + */ + @Override + public Boolean expireAt(byte[] key, long unixTime) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getRequiredPipeline().expireAt(key, unixTime), + JedisConverters.longToBoolean())); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getRequiredTransaction().expireAt(key, unixTime), + JedisConverters.longToBoolean())); + return null; + } + return JedisConverters.toBoolean(connection.getJedis().expireAt(key, unixTime)); + } catch (Exception ex) { + throw connection.convertJedisAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpireAt(byte[], long) @@ -334,12 +351,12 @@ class JedisKeyCommands implements RedisKeyCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().pexpireAt(key, unixTimeInMillis), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().pexpireAt(key, unixTimeInMillis), JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().pexpireAt(key, unixTimeInMillis), + transaction(connection.newJedisResult(connection.getRequiredTransaction().pexpireAt(key, unixTimeInMillis), JedisConverters.longToBoolean())); return null; } @@ -356,14 +373,17 @@ class JedisKeyCommands implements RedisKeyCommands { @Override public Boolean persist(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().persist(key), JedisConverters.longToBoolean())); + pipeline( + connection.newJedisResult(connection.getRequiredPipeline().persist(key), JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction( - connection.newJedisResult(connection.getTransaction().persist(key), JedisConverters.longToBoolean())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().persist(key), + JedisConverters.longToBoolean())); return null; } return JedisConverters.toBoolean(connection.getJedis().persist(key)); @@ -379,15 +399,17 @@ class JedisKeyCommands implements RedisKeyCommands { @Override public Boolean move(byte[] key, int dbIndex) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline( - connection.newJedisResult(connection.getPipeline().move(key, dbIndex), JedisConverters.longToBoolean())); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().move(key, dbIndex), + JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction( - connection.newJedisResult(connection.getTransaction().move(key, dbIndex), JedisConverters.longToBoolean())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().move(key, dbIndex), + JedisConverters.longToBoolean())); return null; } return JedisConverters.toBoolean(connection.getJedis().move(key, dbIndex)); @@ -407,11 +429,11 @@ class JedisKeyCommands implements RedisKeyCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().ttl(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().ttl(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().ttl(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().ttl(key))); return null; } @@ -432,12 +454,13 @@ class JedisKeyCommands implements RedisKeyCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().ttl(key), Converters.secondsToTimeUnit(timeUnit))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().ttl(key), + Converters.secondsToTimeUnit(timeUnit))); return null; } if (isQueueing()) { - transaction( - connection.newJedisResult(connection.getTransaction().ttl(key), Converters.secondsToTimeUnit(timeUnit))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().ttl(key), + Converters.secondsToTimeUnit(timeUnit))); return null; } @@ -458,11 +481,11 @@ class JedisKeyCommands implements RedisKeyCommands { try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().pttl(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().pttl(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().pttl(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().pttl(key))); return null; } @@ -483,12 +506,12 @@ class JedisKeyCommands implements RedisKeyCommands { try { if (isPipelined()) { - pipeline( - connection.newJedisResult(connection.getPipeline().pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().pttl(key), + Converters.millisecondsToTimeUnit(timeUnit))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().pttl(key), + transaction(connection.newJedisResult(connection.getRequiredTransaction().pttl(key), Converters.millisecondsToTimeUnit(timeUnit))); return null; } @@ -506,23 +529,25 @@ class JedisKeyCommands implements RedisKeyCommands { @Override public List sort(byte[] key, SortParameters params) { + Assert.notNull(key, "Key must not be null!"); + SortingParams sortParams = JedisConverters.toSortingParams(params); try { if (isPipelined()) { if (sortParams != null) { - pipeline(connection.newJedisResult(connection.getPipeline().sort(key, sortParams))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sort(key, sortParams))); } else { - pipeline(connection.newJedisResult(connection.getPipeline().sort(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sort(key))); } return null; } if (isQueueing()) { if (sortParams != null) { - transaction(connection.newJedisResult(connection.getTransaction().sort(key, sortParams))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sort(key, sortParams))); } else { - transaction(connection.newJedisResult(connection.getTransaction().sort(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sort(key))); } return null; @@ -538,25 +563,27 @@ class JedisKeyCommands implements RedisKeyCommands { * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters, byte[]) */ @Override - public Long sort(byte[] key, SortParameters params, byte[] storeKey) { + public Long sort(byte[] key, @Nullable SortParameters params, byte[] storeKey) { + + Assert.notNull(key, "Key must not be null!"); SortingParams sortParams = JedisConverters.toSortingParams(params); try { if (isPipelined()) { if (sortParams != null) { - pipeline(connection.newJedisResult(connection.getPipeline().sort(key, sortParams, storeKey))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sort(key, sortParams, storeKey))); } else { - pipeline(connection.newJedisResult(connection.getPipeline().sort(key, storeKey))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sort(key, storeKey))); } return null; } if (isQueueing()) { if (sortParams != null) { - transaction(connection.newJedisResult(connection.getTransaction().sort(key, sortParams, storeKey))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sort(key, sortParams, storeKey))); } else { - transaction(connection.newJedisResult(connection.getTransaction().sort(key, storeKey))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sort(key, storeKey))); } return null; @@ -575,13 +602,15 @@ class JedisKeyCommands implements RedisKeyCommands { @Override public byte[] dump(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().dump(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().dump(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().dump(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().dump(key))); return null; } return connection.getJedis().dump(key); @@ -597,17 +626,21 @@ class JedisKeyCommands implements RedisKeyCommands { @Override public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(serializedValue, "Serialized value must not be null!"); + if (ttlInMillis > Integer.MAX_VALUE) { throw new IllegalArgumentException("TtlInMillis must be less than Integer.MAX_VALUE for restore in Jedis."); } try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().restore(key, (int) ttlInMillis, serializedValue))); + pipeline(connection + .newStatusResult(connection.getRequiredPipeline().restore(key, (int) ttlInMillis, serializedValue))); return; } if (isQueueing()) { - transaction( - connection.newStatusResult(connection.getTransaction().restore(key, (int) ttlInMillis, serializedValue))); + transaction(connection + .newStatusResult(connection.getRequiredTransaction().restore(key, (int) ttlInMillis, serializedValue))); return; } connection.getJedis().restore(key, (int) ttlInMillis, serializedValue); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java index 3b2b9db57..cd5dbf4f3 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisListCommands.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import redis.clients.jedis.Protocol; import java.util.ArrayList; @@ -22,19 +24,17 @@ import java.util.List; import org.springframework.data.redis.connection.RedisListCommands; import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; +import org.springframework.util.Assert; /** * @author Christoph Strobl * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisListCommands implements RedisListCommands { - private final JedisConnection connection; - - JedisListCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; /* * (non-Javadoc) @@ -43,13 +43,15 @@ class JedisListCommands implements RedisListCommands { @Override public Long rPush(byte[] key, byte[]... values) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().rpush(key, values))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().rpush(key, values))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().rpush(key, values))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().rpush(key, values))); return null; } return connection.getJedis().rpush(key, values); @@ -65,13 +67,17 @@ class JedisListCommands implements RedisListCommands { @Override public Long lPush(byte[] key, byte[]... values) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().lpush(key, values))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().lpush(key, values))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().lpush(key, values))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().lpush(key, values))); return null; } return connection.getJedis().lpush(key, values); @@ -86,13 +92,17 @@ class JedisListCommands implements RedisListCommands { */ @Override public Long rPushX(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().rpushx(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().rpushx(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().rpushx(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().rpushx(key, value))); return null; } return connection.getJedis().rpushx(key, value); @@ -108,13 +118,16 @@ class JedisListCommands implements RedisListCommands { @Override public Long lPushX(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().lpushx(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().lpushx(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().lpushx(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().lpushx(key, value))); return null; } return connection.getJedis().lpushx(key, value); @@ -130,13 +143,15 @@ class JedisListCommands implements RedisListCommands { @Override public Long lLen(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().llen(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().llen(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().llen(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().llen(key))); return null; } return connection.getJedis().llen(key); @@ -152,13 +167,15 @@ class JedisListCommands implements RedisListCommands { @Override public List lRange(byte[] key, long start, long end) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().lrange(key, start, end))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().lrange(key, start, end))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().lrange(key, start, end))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().lrange(key, start, end))); return null; } return connection.getJedis().lrange(key, start, end); @@ -174,13 +191,15 @@ class JedisListCommands implements RedisListCommands { @Override public void lTrim(byte[] key, long start, long end) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().ltrim(key, start, end))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().ltrim(key, start, end))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().ltrim(key, start, end))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().ltrim(key, start, end))); return; } connection.getJedis().ltrim(key, start, end); @@ -196,13 +215,15 @@ class JedisListCommands implements RedisListCommands { @Override public byte[] lIndex(byte[] key, long index) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().lindex(key, index))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().lindex(key, index))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().lindex(key, index))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().lindex(key, index))); return null; } return connection.getJedis().lindex(key, index); @@ -218,15 +239,17 @@ class JedisListCommands implements RedisListCommands { @Override public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newJedisResult( - connection.getPipeline().linsert(key, JedisConverters.toListPosition(where), pivot, value))); + connection.getRequiredPipeline().linsert(key, JedisConverters.toListPosition(where), pivot, value))); return null; } if (isQueueing()) { transaction(connection.newJedisResult( - connection.getTransaction().linsert(key, JedisConverters.toListPosition(where), pivot, value))); + connection.getRequiredTransaction().linsert(key, JedisConverters.toListPosition(where), pivot, value))); return null; } return connection.getJedis().linsert(key, JedisConverters.toListPosition(where), pivot, value); @@ -242,13 +265,16 @@ class JedisListCommands implements RedisListCommands { @Override public void lSet(byte[] key, long index, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().lset(key, index, value))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().lset(key, index, value))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().lset(key, index, value))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().lset(key, index, value))); return; } connection.getJedis().lset(key, index, value); @@ -264,13 +290,16 @@ class JedisListCommands implements RedisListCommands { @Override public Long lRem(byte[] key, long count, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().lrem(key, count, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().lrem(key, count, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().lrem(key, count, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().lrem(key, count, value))); return null; } return connection.getJedis().lrem(key, count, value); @@ -286,13 +315,15 @@ class JedisListCommands implements RedisListCommands { @Override public byte[] lPop(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().lpop(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().lpop(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().lpop(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().lpop(key))); return null; } return connection.getJedis().lpop(key); @@ -308,13 +339,15 @@ class JedisListCommands implements RedisListCommands { @Override public byte[] rPop(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().rpop(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().rpop(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().rpop(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().rpop(key))); return null; } return connection.getJedis().rpop(key); @@ -331,13 +364,16 @@ class JedisListCommands implements RedisListCommands { @Override public List bLPop(int timeout, byte[]... keys) { + Assert.notNull(keys, "Key must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().blpop(bXPopArgs(timeout, keys)))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().blpop(bXPopArgs(timeout, keys)))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().blpop(bXPopArgs(timeout, keys)))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().blpop(bXPopArgs(timeout, keys)))); return null; } return connection.getJedis().blpop(timeout, keys); @@ -353,13 +389,16 @@ class JedisListCommands implements RedisListCommands { @Override public List bRPop(int timeout, byte[]... keys) { + Assert.notNull(keys, "Key must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().brpop(bXPopArgs(timeout, keys)))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().brpop(bXPopArgs(timeout, keys)))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().brpop(bXPopArgs(timeout, keys)))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().brpop(bXPopArgs(timeout, keys)))); return null; } return connection.getJedis().brpop(timeout, keys); @@ -375,13 +414,16 @@ class JedisListCommands implements RedisListCommands { @Override public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(dstKey, "Destination key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().rpoplpush(srcKey, dstKey))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().rpoplpush(srcKey, dstKey))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().rpoplpush(srcKey, dstKey))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().rpoplpush(srcKey, dstKey))); return null; } return connection.getJedis().rpoplpush(srcKey, dstKey); @@ -397,13 +439,16 @@ class JedisListCommands implements RedisListCommands { @Override public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(dstKey, "Destination key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().brpoplpush(srcKey, dstKey, timeout))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().brpoplpush(srcKey, dstKey, timeout))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().brpoplpush(srcKey, dstKey, timeout))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().brpoplpush(srcKey, dstKey, timeout))); return null; } return connection.getJedis().brpoplpush(srcKey, dstKey, timeout); @@ -414,8 +459,8 @@ class JedisListCommands implements RedisListCommands { private byte[][] bXPopArgs(int timeout, byte[]... keys) { - final List args = new ArrayList<>(); - for (final byte[] arg : keys) { + List args = new ArrayList<>(); + for (byte[] arg : keys) { args.add(arg); } args.add(Protocol.toByteArray(timeout)); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisScriptingCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisScriptingCommands.java index 395ccab33..b7f2f075e 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisScriptingCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisScriptingCommands.java @@ -15,22 +15,23 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + import java.util.List; import org.springframework.data.redis.connection.RedisScriptingCommands; import org.springframework.data.redis.connection.ReturnType; +import org.springframework.util.Assert; /** * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisScriptingCommands implements RedisScriptingCommands { - private final JedisConnection connection; - - JedisScriptingCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; /* * (non-Javadoc) @@ -38,12 +39,11 @@ class JedisScriptingCommands implements RedisScriptingCommands { */ @Override public void scriptFlush() { - if (isQueueing()) { - throw new UnsupportedOperationException(); - } - if (isPipelined()) { + + if (isQueueing() || isPipelined()) { throw new UnsupportedOperationException(); } + try { connection.getJedis().scriptFlush(); } catch (Exception ex) { @@ -57,12 +57,11 @@ class JedisScriptingCommands implements RedisScriptingCommands { */ @Override public void scriptKill() { - if (isQueueing()) { - throw new UnsupportedOperationException(); - } - if (isPipelined()) { + + if (isQueueing() || isPipelined()) { throw new UnsupportedOperationException(); } + try { connection.getJedis().scriptKill(); } catch (Exception ex) { @@ -76,12 +75,13 @@ class JedisScriptingCommands implements RedisScriptingCommands { */ @Override public String scriptLoad(byte[] script) { - if (isQueueing()) { - throw new UnsupportedOperationException(); - } - if (isPipelined()) { + + Assert.notNull(script, "Script must not be null!"); + + if (isQueueing() || isPipelined()) { throw new UnsupportedOperationException(); } + try { return JedisConverters.toString(connection.getJedis().scriptLoad(script)); } catch (Exception ex) { @@ -95,12 +95,14 @@ class JedisScriptingCommands implements RedisScriptingCommands { */ @Override public List scriptExists(String... scriptSha1) { - if (isQueueing()) { - throw new UnsupportedOperationException(); - } - if (isPipelined()) { + + Assert.notNull(scriptSha1, "Script digests must not be null!"); + Assert.noNullElements(scriptSha1, "Script digests must not contain null elements!"); + + if (isQueueing() || isPipelined()) { throw new UnsupportedOperationException(); } + try { return connection.getJedis().scriptExists(scriptSha1); } catch (Exception ex) { @@ -115,12 +117,13 @@ class JedisScriptingCommands implements RedisScriptingCommands { @Override @SuppressWarnings("unchecked") public T eval(byte[] script, ReturnType returnType, int numKeys, byte[]... keysAndArgs) { - if (isQueueing()) { - throw new UnsupportedOperationException(); - } - if (isPipelined()) { + + Assert.notNull(script, "Script must not be null!"); + + if (isQueueing() || isPipelined()) { throw new UnsupportedOperationException(); } + try { return (T) new JedisScriptReturnConverter(returnType) .convert(connection.getJedis().eval(script, JedisConverters.toBytes(numKeys), keysAndArgs)); @@ -146,12 +149,12 @@ class JedisScriptingCommands implements RedisScriptingCommands { @SuppressWarnings("unchecked") public T evalSha(byte[] scriptSha1, ReturnType returnType, int numKeys, byte[]... keysAndArgs) { - if (isQueueing()) { - throw new UnsupportedOperationException(); - } - if (isPipelined()) { + Assert.notNull(scriptSha1, "Script digest must not be null!"); + + if (isQueueing() || isPipelined()) { throw new UnsupportedOperationException(); } + try { return (T) new JedisScriptReturnConverter(returnType) .convert(connection.getJedis().evalsha(scriptSha1, numKeys, keysAndArgs)); 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 2f351308b..2fd12ec08 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 @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; +import redis.clients.jedis.Jedis; + import java.io.IOException; import java.util.List; @@ -25,8 +27,6 @@ import org.springframework.data.redis.connection.RedisSentinelConnection; import org.springframework.data.redis.connection.RedisServer; import org.springframework.util.Assert; -import redis.clients.jedis.Jedis; - /** * @author Christoph Strobl * @since 1.4 @@ -126,8 +126,8 @@ public class JedisSentinelConnection implements RedisSentinelConnection { Assert.hasText(server.getHost(), "Host must not be 'null' for server to monitor."); Assert.notNull(server.getPort(), "Port must not be 'null' for server to monitor."); Assert.notNull(server.getQuorum(), "Quorum must not be 'null' for server to monitor."); - jedis.sentinelMonitor(server.getName(), server.getHost(), server.getPort().intValue(), server.getQuorum() - .intValue()); + jedis.sentinelMonitor(server.getName(), server.getHost(), server.getPort().intValue(), + server.getQuorum().intValue()); } /* @@ -147,7 +147,7 @@ public class JedisSentinelConnection implements RedisSentinelConnection { /** * Do what ever is required to establish the connection to redis. - * + * * @param jedis */ protected void doInit(Jedis jedis) { @@ -156,7 +156,7 @@ public class JedisSentinelConnection implements RedisSentinelConnection { @Override public boolean isOpen() { - return jedis != null && jedis.isConnected(); + return jedis.isConnected(); } } 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 e90a6361c..477161db8 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisServerCommands.java @@ -15,6 +15,9 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + import java.util.List; import java.util.Properties; @@ -31,15 +34,12 @@ import org.springframework.util.Assert; * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisServerCommands implements RedisServerCommands { private static final String SHUTDOWN_SCRIPT = "return redis.call('SHUTDOWN','%s')"; - private final JedisConnection connection; - - JedisServerCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; /* * (non-Javadoc) @@ -47,13 +47,14 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public void bgReWriteAof() { + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().bgrewriteaof())); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().bgrewriteaof())); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().bgrewriteaof())); + transaction(connection.newStatusResult(connection.getRequiredTransaction().bgrewriteaof())); return; } connection.getJedis().bgrewriteaof(); @@ -68,13 +69,14 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public void bgSave() { + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().bgsave())); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().bgsave())); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().bgsave())); + transaction(connection.newStatusResult(connection.getRequiredTransaction().bgsave())); return; } connection.getJedis().bgsave(); @@ -89,13 +91,14 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public Long lastSave() { + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().lastsave())); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().lastsave())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().lastsave())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().lastsave())); return null; } return connection.getJedis().lastsave(); @@ -110,13 +113,14 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public void save() { + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().save())); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().save())); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().save())); + transaction(connection.newStatusResult(connection.getRequiredTransaction().save())); return; } connection.getJedis().save(); @@ -131,13 +135,14 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public Long dbSize() { + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().dbSize())); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().dbSize())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().dbSize())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().dbSize())); return null; } return connection.getJedis().dbSize(); @@ -152,13 +157,14 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public void flushDb() { + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().flushDB())); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().flushDB())); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().flushDB())); + transaction(connection.newStatusResult(connection.getRequiredTransaction().flushDB())); return; } connection.getJedis().flushDB(); @@ -173,13 +179,14 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public void flushAll() { + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().flushAll())); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().flushAll())); return; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().flushAll())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().flushAll())); return; } connection.getJedis().flushAll(); @@ -194,13 +201,15 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public Properties info() { + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().info(), JedisConverters.stringToProps())); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().info(), JedisConverters.stringToProps())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().info(), JedisConverters.stringToProps())); + transaction( + connection.newJedisResult(connection.getRequiredTransaction().info(), JedisConverters.stringToProps())); return null; } return JedisConverters.toProperties(connection.getJedis().info()); @@ -215,12 +224,13 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public Properties info(String section) { - if (isPipelined()) { - throw new UnsupportedOperationException(); - } - if (isQueueing()) { + + Assert.notNull(section, "Section must not be null!"); + + if (isPipelined() || isQueueing()) { throw new UnsupportedOperationException(); } + try { return JedisConverters.toProperties(connection.getJedis().info(section)); } catch (Exception ex) { @@ -234,13 +244,14 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public void shutdown() { + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().shutdown())); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().shutdown())); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().shutdown())); + transaction(connection.newStatusResult(connection.getRequiredTransaction().shutdown())); return; } connection.getJedis().shutdown(); @@ -269,19 +280,22 @@ class JedisServerCommands implements RedisServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#getConfig(java.lang.String) */ @Override - public Properties getConfig(String param) { + public Properties getConfig(String pattern) { + + Assert.notNull(pattern, "Pattern must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().configGet(param), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().configGet(pattern), Converters.listToPropertiesConverter())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().configGet(param), + transaction(connection.newJedisResult(connection.getRequiredTransaction().configGet(pattern), Converters.listToPropertiesConverter())); return null; } - return Converters.toProperties(connection.getJedis().configGet(param)); + return Converters.toProperties(connection.getJedis().configGet(pattern)); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -293,13 +307,17 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public void setConfig(String param, String value) { + + Assert.notNull(param, "Parameter must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().configSet(param, value))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().configSet(param, value))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().configSet(param, value))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().configSet(param, value))); return; } connection.getJedis().configSet(param, value); @@ -314,13 +332,14 @@ class JedisServerCommands implements RedisServerCommands { */ @Override public void resetConfigStats() { + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().configResetStat())); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().configResetStat())); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().configResetStat())); + transaction(connection.newStatusResult(connection.getRequiredTransaction().configResetStat())); return; } connection.getJedis().configResetStat(); @@ -337,14 +356,13 @@ class JedisServerCommands implements RedisServerCommands { public Long time() { try { - if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().time(), JedisConverters.toTimeConverter())); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().time(), JedisConverters.toTimeConverter())); return null; } - if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().time(), JedisConverters.toTimeConverter())); + transaction( + connection.newJedisResult(connection.getRequiredTransaction().time(), JedisConverters.toTimeConverter())); return null; } return JedisConverters.toTimeConverter().convert(connection.getJedis().time()); @@ -380,6 +398,8 @@ class JedisServerCommands implements RedisServerCommands { @Override public void setClientName(byte[] name) { + Assert.notNull(name, "Name must not be null!"); + if (isPipelined() || isQueueing()) { throw new UnsupportedOperationException("'CLIENT SETNAME' is not suppored in transacton / pipeline mode."); } @@ -422,6 +442,7 @@ class JedisServerCommands implements RedisServerCommands { public void slaveOf(String host, int port) { Assert.hasText(host, "Host must not be null for 'SLAVEOF' command."); + if (isQueueing() || isPipelined()) { throw new UnsupportedOperationException("'SLAVEOF' cannot be called in pipline / transaction mode."); } @@ -442,6 +463,7 @@ class JedisServerCommands implements RedisServerCommands { if (isQueueing() || isPipelined()) { throw new UnsupportedOperationException("'SLAVEOF' cannot be called in pipline / transaction mode."); } + try { this.connection.getJedis().slaveofNoOne(); } catch (Exception e) { @@ -465,17 +487,20 @@ class JedisServerCommands implements RedisServerCommands { @Override public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, long timeout) { - final int timeoutToUse = timeout <= Integer.MAX_VALUE ? (int) timeout : Integer.MAX_VALUE; + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(target, "Target node must not be null!"); + + int timeoutToUse = timeout <= Integer.MAX_VALUE ? (int) timeout : Integer.MAX_VALUE; try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().migrate(JedisConverters.toBytes(target.getHost()), - target.getPort(), key, dbIndex, timeoutToUse))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline() + .migrate(JedisConverters.toBytes(target.getHost()), target.getPort(), key, dbIndex, timeoutToUse))); return; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction() + transaction(connection.newJedisResult(connection.getRequiredTransaction() .migrate(JedisConverters.toBytes(target.getHost()), target.getPort(), key, dbIndex, timeoutToUse))); return; } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java index 1f57a6dd1..1ea70281e 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSetCommands.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import redis.clients.jedis.ScanParams; import java.util.ArrayList; @@ -27,19 +29,17 @@ import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; /** * @author Christoph Strobl * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisSetCommands implements RedisSetCommands { - private final JedisConnection connection; - - JedisSetCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; /* * (non-Javadoc) @@ -47,13 +47,18 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Long sAdd(byte[] key, byte[]... values) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().sadd(key, values))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sadd(key, values))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().sadd(key, values))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sadd(key, values))); return null; } return connection.getJedis().sadd(key, values); @@ -68,13 +73,16 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Long sCard(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().scard(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().scard(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().scard(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().scard(key))); return null; } return connection.getJedis().scard(key); @@ -89,13 +97,17 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Set sDiff(byte[]... keys) { + + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().sdiff(keys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sdiff(keys))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().sdiff(keys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sdiff(keys))); return null; } return connection.getJedis().sdiff(keys); @@ -110,13 +122,18 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Long sDiffStore(byte[] destKey, byte[]... keys) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().sdiffstore(destKey, keys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sdiffstore(destKey, keys))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().sdiffstore(destKey, keys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sdiffstore(destKey, keys))); return null; } return connection.getJedis().sdiffstore(destKey, keys); @@ -131,13 +148,17 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Set sInter(byte[]... keys) { + + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().sinter(keys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sinter(keys))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().sinter(keys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sinter(keys))); return null; } return connection.getJedis().sinter(keys); @@ -152,13 +173,18 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Long sInterStore(byte[] destKey, byte[]... keys) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().sinterstore(destKey, keys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sinterstore(destKey, keys))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().sinterstore(destKey, keys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sinterstore(destKey, keys))); return null; } return connection.getJedis().sinterstore(destKey, keys); @@ -173,13 +199,17 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Boolean sIsMember(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().sismember(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sismember(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().sismember(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sismember(key, value))); return null; } return connection.getJedis().sismember(key, value); @@ -194,13 +224,16 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Set sMembers(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().smembers(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().smembers(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().smembers(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().smembers(key))); return null; } return connection.getJedis().smembers(key); @@ -215,14 +248,19 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { + + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().smove(srcKey, destKey, value), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().smove(srcKey, destKey, value), JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().smove(srcKey, destKey, value), + transaction(connection.newJedisResult(connection.getRequiredTransaction().smove(srcKey, destKey, value), JedisConverters.longToBoolean())); return null; } @@ -238,13 +276,16 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public byte[] sPop(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().spop(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().spop(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().spop(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().spop(key))); return null; } return connection.getJedis().spop(key); @@ -260,13 +301,15 @@ class JedisSetCommands implements RedisSetCommands { @Override public List sPop(byte[] key, long count) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().spop(key, count), ArrayList::new)); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().spop(key, count), ArrayList::new)); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().spop(key, count), ArrayList::new)); + transaction(connection.newJedisResult(connection.getRequiredTransaction().spop(key, count), ArrayList::new)); return null; } return new ArrayList<>(connection.getJedis().spop(key, count)); @@ -281,13 +324,16 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public byte[] sRandMember(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().srandmember(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().srandmember(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().srandmember(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().srandmember(key))); return null; } return connection.getJedis().srandmember(key); @@ -303,17 +349,19 @@ class JedisSetCommands implements RedisSetCommands { @Override public List sRandMember(byte[] key, long count) { + Assert.notNull(key, "Key must not be null!"); + if (count > Integer.MAX_VALUE) { throw new IllegalArgumentException("Count must be less than Integer.MAX_VALUE for sRandMember in Jedis."); } try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().srandmember(key, (int) count))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().srandmember(key, (int) count))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().srandmember(key, (int) count))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().srandmember(key, (int) count))); return null; } return connection.getJedis().srandmember(key, (int) count); @@ -328,13 +376,18 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Long sRem(byte[] key, byte[]... values) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().srem(key, values))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().srem(key, values))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().srem(key, values))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().srem(key, values))); return null; } return connection.getJedis().srem(key, values); @@ -349,13 +402,17 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Set sUnion(byte[]... keys) { + + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().sunion(keys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sunion(keys))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().sunion(keys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sunion(keys))); return null; } return connection.getJedis().sunion(keys); @@ -370,13 +427,18 @@ class JedisSetCommands implements RedisSetCommands { */ @Override public Long sUnionStore(byte[] destKey, byte[]... keys) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().sunionstore(destKey, keys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().sunionstore(destKey, keys))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().sunionstore(destKey, keys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().sunionstore(destKey, keys))); return null; } return connection.getJedis().sunionstore(destKey, keys); @@ -403,6 +465,8 @@ class JedisSetCommands implements RedisSetCommands { */ public Cursor sScan(byte[] key, long cursorId, ScanOptions options) { + Assert.notNull(key, "Key must not be null!"); + return new KeyBoundCursor(key, cursorId, options) { @Override diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java index 2f523eb56..a6c4f5786 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisStringCommands.java @@ -15,6 +15,9 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -30,24 +33,27 @@ import org.springframework.util.ObjectUtils; * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisStringCommands implements RedisStringCommands { - private final JedisConnection connection; - - JedisStringCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#get(byte[]) + */ @Override public byte[] get(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().get(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().get(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().get(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().get(key))); return null; } @@ -57,35 +63,48 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#getSet(byte[], byte[]) + */ @Override public byte[] getSet(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().getSet(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().getSet(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().getSet(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().getSet(key, value))); return null; } return connection.getJedis().getSet(key, value); } catch (Exception ex) { throw convertJedisAccessException(ex); } - } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#mGet(byte[][]) + */ @Override public List mGet(byte[]... keys) { + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().mget(keys))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().mget(keys))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().mget(keys))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().mget(keys))); return null; } return connection.getJedis().mget(keys); @@ -94,16 +113,23 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[]) + */ @Override public void set(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().set(key, value))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().set(key, value))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().set(key, value))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().set(key, value))); return; } connection.getJedis().set(key, value); @@ -112,9 +138,15 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[], org.springframework.data.redis.core.types.Expiration, org.springframework.data.redis.connection.RedisStringCommands.SetOption) + */ @Override public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); Assert.notNull(expiration, "Expiration must not be null!"); Assert.notNull(option, "Option must not be null!"); @@ -130,12 +162,12 @@ class JedisStringCommands implements RedisStringCommands { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().set(key, value, nxxx))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().set(key, value, nxxx))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().set(key, value, nxxx))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().set(key, value, nxxx))); return; } @@ -169,7 +201,7 @@ class JedisStringCommands implements RedisStringCommands { } pipeline(connection.newStatusResult( - connection.getPipeline().set(key, value, nxxx, expx, (int) expiration.getExpirationTime()))); + connection.getRequiredPipeline().set(key, value, nxxx, expx, (int) expiration.getExpirationTime()))); return; } if (isQueueing()) { @@ -180,7 +212,7 @@ class JedisStringCommands implements RedisStringCommands { } transaction(connection.newStatusResult( - connection.getTransaction().set(key, value, nxxx, expx, (int) expiration.getExpirationTime()))); + connection.getRequiredTransaction().set(key, value, nxxx, expx, (int) expiration.getExpirationTime()))); return; } @@ -193,18 +225,25 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setNX(byte[], byte[]) + */ @Override public Boolean setNX(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline( - connection.newJedisResult(connection.getPipeline().setnx(key, value), JedisConverters.longToBoolean())); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().setnx(key, value), + JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction( - connection.newJedisResult(connection.getTransaction().setnx(key, value), JedisConverters.longToBoolean())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().setnx(key, value), + JedisConverters.longToBoolean())); return null; } return JedisConverters.toBoolean(connection.getJedis().setnx(key, value)); @@ -214,19 +253,27 @@ class JedisStringCommands implements RedisStringCommands { } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setEx(byte[], long, byte[]) + */ @Override public void setEx(byte[] key, long seconds, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + if (seconds > Integer.MAX_VALUE) { throw new IllegalArgumentException("Time must be less than Integer.MAX_VALUE for setEx in Jedis."); } try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().setex(key, (int) seconds, value))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().setex(key, (int) seconds, value))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().setex(key, (int) seconds, value))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().setex(key, (int) seconds, value))); return; } connection.getJedis().setex(key, (int) seconds, value); @@ -235,16 +282,23 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[]) + */ @Override public void pSetEx(byte[] key, long milliseconds, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().psetex(key, milliseconds, value))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().psetex(key, milliseconds, value))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().psetex(key, milliseconds, value))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().psetex(key, milliseconds, value))); return; } connection.getJedis().psetex(key, milliseconds, value); @@ -253,16 +307,24 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#mSet(java.util.Map) + */ @Override public void mSet(Map tuples) { + Assert.notNull(tuples, "Tuples must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().mset(JedisConverters.toByteArrays(tuples)))); + pipeline( + connection.newStatusResult(connection.getRequiredPipeline().mset(JedisConverters.toByteArrays(tuples)))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().mset(JedisConverters.toByteArrays(tuples)))); + transaction( + connection.newStatusResult(connection.getRequiredTransaction().mset(JedisConverters.toByteArrays(tuples)))); return; } connection.getJedis().mset(JedisConverters.toByteArrays(tuples)); @@ -271,18 +333,26 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#mSetNX(java.util.Map) + */ @Override public Boolean mSetNX(Map tuples) { + Assert.notNull(tuples, "Tuples must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().msetnx(JedisConverters.toByteArrays(tuples)), - JedisConverters.longToBoolean())); + pipeline( + connection.newJedisResult(connection.getRequiredPipeline().msetnx(JedisConverters.toByteArrays(tuples)), + JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().msetnx(JedisConverters.toByteArrays(tuples)), - JedisConverters.longToBoolean())); + transaction( + connection.newJedisResult(connection.getRequiredTransaction().msetnx(JedisConverters.toByteArrays(tuples)), + JedisConverters.longToBoolean())); return null; } return JedisConverters.toBoolean(connection.getJedis().msetnx(JedisConverters.toByteArrays(tuples))); @@ -291,35 +361,46 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#incr(byte[]) + */ @Override public Long incr(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().incr(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().incr(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().incr(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().incr(key))); return null; } return connection.getJedis().incr(key); } catch (Exception ex) { throw convertJedisAccessException(ex); } - } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#incrBy(byte[], long) + */ @Override public Long incrBy(byte[] key, long value) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().incrBy(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().incrBy(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().incrBy(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().incrBy(key, value))); return null; } return connection.getJedis().incrBy(key, value); @@ -329,16 +410,22 @@ class JedisStringCommands implements RedisStringCommands { } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#incrBy(byte[], double) + */ @Override public Double incrBy(byte[] key, double value) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().incrByFloat(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().incrByFloat(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().incrByFloat(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().incrByFloat(key, value))); return null; } return connection.getJedis().incrByFloat(key, value); @@ -347,16 +434,22 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#decr(byte[]) + */ @Override public Long decr(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().decr(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().decr(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().decr(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().decr(key))); return null; } return connection.getJedis().decr(key); @@ -366,16 +459,22 @@ class JedisStringCommands implements RedisStringCommands { } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#decrBy(byte[], long) + */ @Override public Long decrBy(byte[] key, long value) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().decrBy(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().decrBy(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().decrBy(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().decrBy(key, value))); return null; } return connection.getJedis().decrBy(key, value); @@ -384,16 +483,23 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#append(byte[], byte[]) + */ @Override public Long append(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().append(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().append(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().append(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().append(key, value))); return null; } return connection.getJedis().append(key, value); @@ -402,21 +508,27 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#getRange(byte[], long, long) + */ @Override public byte[] getRange(byte[] key, long start, long end) { + Assert.notNull(key, "Key must not be null!"); + if (start > Integer.MAX_VALUE || end > Integer.MAX_VALUE) { throw new IllegalArgumentException("Start and end must be less than Integer.MAX_VALUE for getRange in Jedis."); } try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().substr(key, (int) start, (int) end), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().substr(key, (int) start, (int) end), JedisConverters.stringToBytes())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().substr(key, (int) start, (int) end), + transaction(connection.newJedisResult(connection.getRequiredTransaction().substr(key, (int) start, (int) end), JedisConverters.stringToBytes())); return null; } @@ -426,34 +538,47 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setRange(byte[], byte[], long) + */ @Override - public void setRange(byte[] key, byte[] value, long start) { + public void setRange(byte[] key, byte[] value, long offset) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); try { if (isPipelined()) { - pipeline(connection.newStatusResult(connection.getPipeline().setrange(key, start, value))); + pipeline(connection.newStatusResult(connection.getRequiredPipeline().setrange(key, offset, value))); return; } if (isQueueing()) { - transaction(connection.newStatusResult(connection.getTransaction().setrange(key, start, value))); + transaction(connection.newStatusResult(connection.getRequiredTransaction().setrange(key, offset, value))); return; } - connection.getJedis().setrange(key, start, value); + connection.getJedis().setrange(key, offset, value); } catch (Exception ex) { throw convertJedisAccessException(ex); } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#getBit(byte[], long) + */ @Override public Boolean getBit(byte[] key, long offset) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().getbit(key, offset))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().getbit(key, offset))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().getbit(key, offset))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().getbit(key, offset))); return null; } // compatibility check for Jedis 2.0.0 @@ -469,18 +594,25 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setBit(byte[], long, boolean) + */ @Override public Boolean setBit(byte[] key, long offset, boolean value) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().setbit(key, offset, JedisConverters.toBit(value)))); + pipeline(connection + .newJedisResult(connection.getRequiredPipeline().setbit(key, offset, JedisConverters.toBit(value)))); return null; } if (isQueueing()) { - transaction( - connection.newJedisResult(connection.getTransaction().setbit(key, offset, JedisConverters.toBit(value)))); + transaction(connection + .newJedisResult(connection.getRequiredTransaction().setbit(key, offset, JedisConverters.toBit(value)))); return null; } return connection.getJedis().setbit(key, offset, JedisConverters.toBit(value)); @@ -490,16 +622,22 @@ class JedisStringCommands implements RedisStringCommands { } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#bitCount(byte[]) + */ @Override public Long bitCount(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().bitcount(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().bitcount(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().bitcount(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().bitcount(key))); return null; } return connection.getJedis().bitcount(key); @@ -508,39 +646,53 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#bitCount(byte[], long, long) + */ @Override - public Long bitCount(byte[] key, long begin, long end) { + public Long bitCount(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().bitcount(key, begin, end))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().bitcount(key, start, end))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().bitcount(key, begin, end))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().bitcount(key, start, end))); return null; } - return connection.getJedis().bitcount(key, begin, end); + return connection.getJedis().bitcount(key, start, end); } catch (Exception ex) { throw convertJedisAccessException(ex); } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#bitOp(org.springframework.data.redis.connection.RedisStringCommands.BitOperation, byte[], byte[][]) + */ @Override public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + Assert.notNull(op, "BitOperation must not be null!"); + Assert.notNull(destination, "Destination key must not be null!"); + if (op == BitOperation.NOT && keys.length > 1) { throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); } + try { if (isPipelined()) { - pipeline( - connection.newJedisResult(connection.getPipeline().bitop(JedisConverters.toBitOp(op), destination, keys))); + pipeline(connection + .newJedisResult(connection.getRequiredPipeline().bitop(JedisConverters.toBitOp(op), destination, keys))); return null; } if (isQueueing()) { transaction(connection - .newJedisResult(connection.getTransaction().bitop(JedisConverters.toBitOp(op), destination, keys))); + .newJedisResult(connection.getRequiredTransaction().bitop(JedisConverters.toBitOp(op), destination, keys))); return null; } return connection.getJedis().bitop(JedisConverters.toBitOp(op), destination, keys); @@ -549,16 +701,22 @@ class JedisStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#strLen(byte[]) + */ @Override public Long strLen(byte[] key) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().strlen(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().strlen(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().strlen(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().strlen(key))); return null; } return connection.getJedis().strlen(key); diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisSubscription.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSubscription.java index 2cc21b09c..865a2a534 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisSubscription.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisSubscription.java @@ -1,12 +1,12 @@ /* - * Copyright 2011-2013 the original author or authors. - * + * Copyright 2011-2017 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 - * + * * http://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. @@ -15,21 +15,23 @@ */ package org.springframework.data.redis.connection.jedis; +import redis.clients.jedis.BinaryJedisPubSub; + import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.util.AbstractSubscription; - -import redis.clients.jedis.BinaryJedisPubSub; +import org.springframework.lang.Nullable; /** * Jedis specific subscription. - * + * * @author Costin Leau */ class JedisSubscription extends AbstractSubscription { private final BinaryJedisPubSub jedisPubSub; - JedisSubscription(MessageListener listener, BinaryJedisPubSub jedisPubSub, byte[][] channels, byte[][] patterns) { + JedisSubscription(MessageListener listener, BinaryJedisPubSub jedisPubSub, @Nullable byte[][] channels, + @Nullable byte[][] patterns) { super(listener, channels, patterns); this.jedisPubSub = jedisPubSub; } 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 edcea0c96..62016840a 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 @@ -54,7 +54,7 @@ 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 */ @@ -68,7 +68,7 @@ public abstract class JedisUtils { /** * Converts the given, native Jedis exception to Spring's DAO hierarchy. - * + * * @param ex Jedis exception * @return converted exception */ @@ -86,7 +86,7 @@ public abstract class JedisUtils { /** * Converts the given, native, runtime Jedis exception to Spring's DAO hierarchy. - * + * * @param ex Jedis runtime/unchecked exception * @return converted exception */ @@ -256,8 +256,8 @@ public abstract class JedisUtils { } static byte[][] bXPopArgs(int timeout, byte[]... keys) { - final List args = new ArrayList<>(); - for (final byte[] arg : keys) { + List args = new ArrayList<>(); + for (byte[] arg : keys) { args.add(arg); } args.add(Protocol.toByteArray(timeout)); 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 38cb617a4..efaa063e8 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisZSetCommands.java @@ -15,10 +15,13 @@ */ package org.springframework.data.redis.connection.jedis; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import redis.clients.jedis.ScanParams; import redis.clients.jedis.ScanResult; import redis.clients.jedis.ZParams; +import java.nio.charset.StandardCharsets; import java.util.Set; import org.springframework.data.redis.connection.RedisZSetCommands; @@ -27,20 +30,19 @@ import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** * @author Christoph Strobl * @author Clement Ong + * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class JedisZSetCommands implements RedisZSetCommands { - private final JedisConnection connection; - - JedisZSetCommands(JedisConnection connection) { - this.connection = connection; - } + private final @NonNull JedisConnection connection; /* * (non-Javadoc) @@ -49,14 +51,17 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Boolean zAdd(byte[] key, double score, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zadd(key, score, value), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zadd(key, score, value), JedisConverters.longToBoolean())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zadd(key, score, value), + transaction(connection.newJedisResult(connection.getRequiredTransaction().zadd(key, score, value), JedisConverters.longToBoolean())); return null; } @@ -73,14 +78,18 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Long zAdd(byte[] key, Set tuples) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(tuples, "Tuples must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zadd(key, JedisConverters.toTupleMap(tuples)))); + pipeline( + connection.newJedisResult(connection.getRequiredPipeline().zadd(key, JedisConverters.toTupleMap(tuples)))); return null; } if (isQueueing()) { - transaction( - connection.newJedisResult(connection.getTransaction().zadd(key, JedisConverters.toTupleMap(tuples)))); + transaction(connection + .newJedisResult(connection.getRequiredTransaction().zadd(key, JedisConverters.toTupleMap(tuples)))); return null; } return connection.getJedis().zadd(key, JedisConverters.toTupleMap(tuples)); @@ -91,66 +100,30 @@ class JedisZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRem(byte[], byte[][]) */ @Override - public Long zCard(byte[] key) { + public Long zRem(byte[] key, byte[]... values) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zcard(key))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrem(key, values))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zcard(key))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrem(key, values))); return null; } - return connection.getJedis().zcard(key); + return connection.getJedis().zrem(key, values); } catch (Exception ex) { throw convertJedisAccessException(ex); } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], double, double) - */ - @Override - public Long zCount(byte[] key, double min, double max) { - - try { - if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zcount(key, min, max))); - return null; - } - if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zcount(key, min, max))); - return null; - } - return connection.getJedis().zcount(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zCount(byte[] key, Range range) { - - if (isPipelined() || isQueueing()) { - throw new UnsupportedOperationException( - "ZCOUNT not implemented in jedis for binary protocol on transaction and pipeline"); - } - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - return connection.getJedis().zcount(key, min, max); - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zIncrBy(byte[], double, byte[]) @@ -158,13 +131,16 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Double zIncrBy(byte[] key, double increment, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zincrby(key, increment, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zincrby(key, increment, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zincrby(key, increment, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zincrby(key, increment, value))); return null; } return connection.getJedis().zincrby(key, increment, value); @@ -175,23 +151,24 @@ class JedisZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[]) */ @Override - public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + public Long zRank(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); try { - ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); - if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zinterstore(destKey, zparams, sets))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrank(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zinterstore(destKey, zparams, sets))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrank(key, value))); return null; } - return connection.getJedis().zinterstore(destKey, zparams, sets); + return connection.getJedis().zrank(key, value); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -199,21 +176,23 @@ class JedisZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], byte[][]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRank(byte[], byte[]) */ @Override - public Long zInterStore(byte[] destKey, byte[]... sets) { + public Long zRevRank(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zinterstore(destKey, sets))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrevrank(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zinterstore(destKey, sets))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrevrank(key, value))); return null; } - return connection.getJedis().zinterstore(destKey, sets); + return connection.getJedis().zrevrank(key, value); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -226,13 +205,15 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Set zRange(byte[] key, long start, long end) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zrange(key, start, end))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrange(key, start, end))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zrange(key, start, end))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrange(key, start, end))); return null; } return connection.getJedis().zrange(key, start, end); @@ -248,14 +229,16 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Set zRangeWithScores(byte[] key, long start, long end) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zrangeWithScores(key, start, end), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrangeWithScores(key, start, end), JedisConverters.tupleSetToTupleSet())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zrangeWithScores(key, start, end), + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrangeWithScores(key, start, end), JedisConverters.tupleSetToTupleSet())); return null; } @@ -266,54 +249,14 @@ class JedisZSetCommands implements RedisZSetCommands { } /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - public Set zRangeByLex(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); - - byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(connection.newJedisResult( - connection.getPipeline().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); - } else { - pipeline(connection.newJedisResult(connection.getPipeline().zrangeByLex(key, min, max))); - } - return null; - } - - if (isQueueing()) { - if (limit != null) { - transaction(connection.newJedisResult( - connection.getTransaction().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); - } else { - transaction(connection.newJedisResult(connection.getTransaction().zrangeByLex(key, min, max))); - } - return null; - } - - if (limit != null) { - return connection.getJedis().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); - } - return connection.getJedis().zrangeByLex(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRangeByScoreWithScores(byte[] key, Range range, @Nullable Limit limit) { - Assert.notNull(range, "Range cannot be null for ZRANGEBYSCORE."); + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); @@ -321,53 +264,10 @@ class JedisZSetCommands implements RedisZSetCommands { try { if (isPipelined()) { if (limit != null) { - pipeline(connection.newJedisResult( - connection.getPipeline().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrangeByScoreWithScores(key, min, max, + limit.getOffset(), limit.getCount()), JedisConverters.tupleSetToTupleSet())); } else { - pipeline(connection.newJedisResult(connection.getPipeline().zrangeByScore(key, min, max))); - } - return null; - } - - if (isQueueing()) { - if (limit != null) { - transaction(connection.newJedisResult( - connection.getTransaction().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); - } else { - transaction(connection.newJedisResult(connection.getTransaction().zrangeByScore(key, min, max))); - } - return null; - } - - if (limit != null) { - return connection.getJedis().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); - } - return connection.getJedis().zrangeByScore(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range cannot be null for ZRANGEBYSCOREWITHSCORES."); - - byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); - byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (isPipelined()) { - if (limit != null) { - pipeline(connection.newJedisResult( - connection.getPipeline().zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount()), - JedisConverters.tupleSetToTupleSet())); - } else { - pipeline(connection.newJedisResult(connection.getPipeline().zrangeByScoreWithScores(key, min, max), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrangeByScoreWithScores(key, min, max), JedisConverters.tupleSetToTupleSet())); } return null; @@ -375,12 +275,12 @@ class JedisZSetCommands implements RedisZSetCommands { if (isQueueing()) { if (limit != null) { - transaction(connection.newJedisResult( - connection.getTransaction().zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount()), - JedisConverters.tupleSetToTupleSet())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrangeByScoreWithScores(key, min, + max, limit.getOffset(), limit.getCount()), JedisConverters.tupleSetToTupleSet())); } else { - transaction(connection.newJedisResult(connection.getTransaction().zrangeByScoreWithScores(key, min, max), - JedisConverters.tupleSetToTupleSet())); + transaction( + connection.newJedisResult(connection.getRequiredTransaction().zrangeByScoreWithScores(key, min, max), + JedisConverters.tupleSetToTupleSet())); } return null; } @@ -395,6 +295,30 @@ class JedisZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRange(byte[], long, long) + */ + @Override + public Set zRevRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrevrange(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrevrange(key, start, end))); + return null; + } + return connection.getJedis().zrevrange(key, start, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeWithScores(byte[], long, long) @@ -402,14 +326,16 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Set zRevRangeWithScores(byte[] key, long start, long end) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zrevrangeWithScores(key, start, end), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrevrangeWithScores(key, start, end), JedisConverters.tupleSetToTupleSet())); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zrevrangeWithScores(key, start, end), + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrevrangeWithScores(key, start, end), JedisConverters.tupleSetToTupleSet())); return null; } @@ -417,17 +343,17 @@ class JedisZSetCommands implements RedisZSetCommands { } catch (Exception ex) { throw convertJedisAccessException(ex); } - } /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ @Override - public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScore(byte[] key, Range range, @Nullable Limit limit) { - Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCORE."); + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range for ZREVRANGEBYSCORE must not be null!"); byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); @@ -436,19 +362,19 @@ class JedisZSetCommands implements RedisZSetCommands { if (isPipelined()) { if (limit != null) { pipeline(connection.newJedisResult( - connection.getPipeline().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()))); + connection.getRequiredPipeline().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()))); } else { - pipeline(connection.newJedisResult(connection.getPipeline().zrevrangeByScore(key, max, min))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrevrangeByScore(key, max, min))); } return null; } if (isQueueing()) { if (limit != null) { - transaction(connection.newJedisResult( - connection.getTransaction().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrevrangeByScore(key, max, min, + limit.getOffset(), limit.getCount()))); } else { - transaction(connection.newJedisResult(connection.getTransaction().zrevrangeByScore(key, max, min))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrevrangeByScore(key, max, min))); } return null; } @@ -463,13 +389,14 @@ class JedisZSetCommands implements RedisZSetCommands { } /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ @Override - public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + public Set zRevRangeByScoreWithScores(byte[] key, Range range, @Nullable Limit limit) { - Assert.notNull(range, "Range cannot be null for ZREVRANGEBYSCOREWITHSCORES."); + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range for ZREVRANGEBYSCOREWITHSCORES must not be null!"); byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); @@ -477,11 +404,10 @@ class JedisZSetCommands implements RedisZSetCommands { try { if (isPipelined()) { if (limit != null) { - pipeline(connection.newJedisResult( - connection.getPipeline().zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount()), - JedisConverters.tupleSetToTupleSet())); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrevrangeByScoreWithScores(key, max, min, + limit.getOffset(), limit.getCount()), JedisConverters.tupleSetToTupleSet())); } else { - pipeline(connection.newJedisResult(connection.getPipeline().zrevrangeByScoreWithScores(key, max, min), + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrevrangeByScoreWithScores(key, max, min), JedisConverters.tupleSetToTupleSet())); } return null; @@ -489,11 +415,12 @@ class JedisZSetCommands implements RedisZSetCommands { if (isQueueing()) { if (limit != null) { - transaction(connection.newJedisResult(connection.getTransaction().zrevrangeByScoreWithScores(key, max, min, - limit.getOffset(), limit.getCount()), JedisConverters.tupleSetToTupleSet())); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrevrangeByScoreWithScores(key, max, + min, limit.getOffset(), limit.getCount()), JedisConverters.tupleSetToTupleSet())); } else { - transaction(connection.newJedisResult(connection.getTransaction().zrevrangeByScoreWithScores(key, max, min), - JedisConverters.tupleSetToTupleSet())); + transaction( + connection.newJedisResult(connection.getRequiredTransaction().zrevrangeByScoreWithScores(key, max, min), + JedisConverters.tupleSetToTupleSet())); } return null; } @@ -510,21 +437,23 @@ class JedisZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], double, double) */ @Override - public Long zRank(byte[] key, byte[] value) { + public Long zCount(byte[] key, double min, double max) { + + Assert.notNull(key, "Key must not be null!"); try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zrank(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zcount(key, min, max))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zrank(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zcount(key, min, max))); return null; } - return connection.getJedis().zrank(key, value); + return connection.getJedis().zcount(key, min, max); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -532,114 +461,43 @@ class JedisZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRem(byte[], byte[][]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) */ @Override - public Long zRem(byte[] key, byte[]... values) { + public Long zCount(byte[] key, Range range) { - try { - if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zrem(key, values))); - return null; - } - if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zrem(key, values))); - return null; - } - return connection.getJedis().zrem(key, values); - } catch (Exception ex) { - throw convertJedisAccessException(ex); + Assert.notNull(key, "Key must not be null!"); + + if (isPipelined() || isQueueing()) { + throw new UnsupportedOperationException( + "ZCOUNT not implemented in jedis for binary protocol on transaction and pipeline"); } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRange(byte[], long, long) - */ - @Override - public Long zRemRange(byte[] key, long start, long end) { - - try { - if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zremrangeByRank(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zremrangeByRank(key, start, end))); - return null; - } - return connection.getJedis().zremrangeByRank(key, start, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zRemRangeByScore(byte[] key, Range range) { - - Assert.notNull(range, "Range cannot be null for ZREMRANGEBYSCORE."); + // TODO: Implement zcount for pipeline/tx. byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); - - try { - if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zremrangeByScore(key, min, max))); - return null; - } - if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zremrangeByScore(key, min, max))); - return null; - } - return connection.getJedis().zremrangeByScore(key, min, max); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } + return connection.getJedis().zcount(key, min, max); } /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRange(byte[], long, long) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) */ @Override - public Set zRevRange(byte[] key, long start, long end) { + public Long zCard(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zrevrange(key, start, end))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zcard(key))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zrevrange(key, start, end))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zcard(key))); return null; } - return connection.getJedis().zrevrange(key, start, end); - } catch (Exception ex) { - throw convertJedisAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRank(byte[], byte[]) - */ - @Override - public Long zRevRank(byte[] key, byte[] value) { - - try { - if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zrevrank(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zrevrank(key, value))); - return null; - } - return connection.getJedis().zrevrank(key, value); + return connection.getJedis().zcard(key); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -652,13 +510,16 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Double zScore(byte[] key, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zscore(key, value))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zscore(key, value))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zscore(key, value))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zscore(key, value))); return null; } return connection.getJedis().zscore(key, value); @@ -667,6 +528,58 @@ class JedisZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRange(byte[], long, long) + */ + @Override + public Long zRemRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zremrangeByRank(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getRequiredTransaction().zremrangeByRank(key, start, end))); + return null; + } + return connection.getJedis().zremrangeByRank(key, start, end); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRemRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) + */ + @Override + public Long zRemRangeByScore(byte[] key, Range range) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range for ZREMRANGEBYSCORE must not be null!"); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zremrangeByScore(key, min, max))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getRequiredTransaction().zremrangeByScore(key, min, max))); + return null; + } + return connection.getJedis().zremrangeByScore(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) @@ -674,15 +587,19 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + try { ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zunionstore(destKey, zparams, sets))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zunionstore(destKey, zparams, sets))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zunionstore(destKey, zparams, sets))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zunionstore(destKey, zparams, sets))); return null; } return connection.getJedis().zunionstore(destKey, zparams, sets); @@ -698,13 +615,17 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Long zUnionStore(byte[] destKey, byte[]... sets) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + try { if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zunionstore(destKey, sets))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zunionstore(destKey, sets))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zunionstore(destKey, sets))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zunionstore(destKey, sets))); return null; } return connection.getJedis().zunionstore(destKey, sets); @@ -713,6 +634,60 @@ class JedisZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + + try { + ZParams zparams = new ZParams().weights(weights).aggregate(ZParams.Aggregate.valueOf(aggregate.name())); + + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zinterstore(destKey, zparams, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getRequiredTransaction().zinterstore(destKey, zparams, sets))); + return null; + } + return connection.getJedis().zinterstore(destKey, zparams, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, byte[]... sets) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + + try { + if (isPipelined()) { + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zinterstore(destKey, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newJedisResult(connection.getRequiredTransaction().zinterstore(destKey, sets))); + return null; + } + return connection.getJedis().zinterstore(destKey, sets); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zScan(byte[], org.springframework.data.redis.core.ScanOptions) @@ -731,6 +706,8 @@ class JedisZSetCommands implements RedisZSetCommands { */ public Cursor zScan(byte[] key, Long cursorId, ScanOptions options) { + Assert.notNull(key, "Key must not be null!"); + return new KeyBoundCursor(key, cursorId, options) { @Override @@ -748,6 +725,7 @@ class JedisZSetCommands implements RedisZSetCommands { JedisConverters.tuplesToTuples().convert(result.getResult())); } + @Override protected void doClose() { JedisZSetCommands.this.connection.close(); }; @@ -762,14 +740,16 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScore(byte[] key, String min, String max) { + Assert.notNull(key, "Key must not be null!"); + try { - String keyStr = new String(key, "UTF-8"); + String keyStr = new String(key, StandardCharsets.UTF_8); if (isPipelined()) { - pipeline(connection.newJedisResult(connection.getPipeline().zrangeByScore(keyStr, min, max))); + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrangeByScore(keyStr, min, max))); return null; } if (isQueueing()) { - transaction(connection.newJedisResult(connection.getTransaction().zrangeByScore(keyStr, min, max))); + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrangeByScore(keyStr, min, max))); return null; } return JedisConverters.stringSetToByteSet().convert(connection.getJedis().zrangeByScore(keyStr, min, max)); @@ -785,6 +765,8 @@ class JedisZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { + Assert.notNull(key, "Key must not be null!"); + if (offset > Integer.MAX_VALUE || count > Integer.MAX_VALUE) { throw new IllegalArgumentException( @@ -792,15 +774,15 @@ class JedisZSetCommands implements RedisZSetCommands { } try { - String keyStr = new String(key, "UTF-8"); + String keyStr = new String(key, StandardCharsets.UTF_8); if (isPipelined()) { - pipeline(connection - .newJedisResult(connection.getPipeline().zrangeByScore(keyStr, min, max, (int) offset, (int) count))); + pipeline(connection.newJedisResult( + connection.getRequiredPipeline().zrangeByScore(keyStr, min, max, (int) offset, (int) count))); return null; } if (isQueueing()) { - transaction(connection - .newJedisResult(connection.getTransaction().zrangeByScore(keyStr, min, max, (int) offset, (int) count))); + transaction(connection.newJedisResult( + connection.getRequiredTransaction().zrangeByScore(keyStr, min, max, (int) offset, (int) count))); return null; } return JedisConverters.stringSetToByteSet() @@ -810,6 +792,92 @@ class JedisZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScore(byte[] key, Range range, @Nullable Limit limit) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); + + byte[] min = JedisConverters.boundaryToBytesForZRange(range.getMin(), JedisConverters.NEGATIVE_INFINITY_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newJedisResult( + connection.getRequiredPipeline().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrangeByScore(key, min, max))); + } + return null; + } + + if (isQueueing()) { + if (limit != null) { + transaction(connection.newJedisResult( + connection.getRequiredTransaction().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrangeByScore(key, min, max))); + } + return null; + } + + if (limit != null) { + return connection.getJedis().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); + } + return connection.getJedis().zrangeByScore(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByLex(byte[] key, Range range, @Nullable Limit limit) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range for ZRANGEBYLEX must not be null!"); + + byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.MINUS_BYTES); + byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.PLUS_BYTES); + + try { + if (isPipelined()) { + if (limit != null) { + pipeline(connection.newJedisResult( + connection.getRequiredPipeline().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + pipeline(connection.newJedisResult(connection.getRequiredPipeline().zrangeByLex(key, min, max))); + } + return null; + } + + if (isQueueing()) { + if (limit != null) { + transaction(connection.newJedisResult( + connection.getRequiredTransaction().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()))); + } else { + transaction(connection.newJedisResult(connection.getRequiredTransaction().zrangeByLex(key, min, max))); + } + return null; + } + + if (limit != null) { + return connection.getJedis().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); + } + return connection.getJedis().zrangeByLex(key, min, max); + } catch (Exception ex) { + throw convertJedisAccessException(ex); + } + } + private boolean isPipelined() { return connection.isPipelined(); } diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/package-info.java b/src/main/java/org/springframework/data/redis/connection/jedis/package-info.java index ad559c158..6e91ceb33 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/package-info.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/package-info.java @@ -2,4 +2,5 @@ * Connection package for Jedis library. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.connection.jedis; 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 7073e0fe4..9e5bbaf35 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 @@ -247,11 +247,11 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau * @see org.springframework.data.redis.connection.RedisClusterCommands#getClusterSlaves(org.springframework.data.redis.connection.RedisClusterNode) */ @Override - public Set clusterGetSlaves(final RedisClusterNode master) { + public Set clusterGetSlaves(RedisClusterNode master) { Assert.notNull(master, "Master must not be null!"); - final RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(master); + RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(master); return clusterCommandExecutor .executeCommandOnSingleNode((LettuceClusterCommandCallback>) client -> LettuceConverters @@ -305,7 +305,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau * @see org.springframework.data.redis.connection.RedisClusterCommands#addSlots(org.springframework.data.redis.connection.RedisClusterNode, int[]) */ @Override - public void clusterAddSlots(RedisClusterNode node, final int... slots) { + public void clusterAddSlots(RedisClusterNode node, int... slots) { clusterCommandExecutor.executeCommandOnSingleNode( (LettuceClusterCommandCallback) client -> client.clusterAddSlots(slots), node); @@ -329,7 +329,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau * @see org.springframework.data.redis.connection.RedisClusterCommands#deleteSlots(org.springframework.data.redis.connection.RedisClusterNode, int[]) */ @Override - public void clusterDeleteSlots(RedisClusterNode node, final int... slots) { + public void clusterDeleteSlots(RedisClusterNode node, int... slots) { clusterCommandExecutor.executeCommandOnSingleNode( (LettuceClusterCommandCallback) client -> client.clusterDelSlots(slots), node); } @@ -351,10 +351,10 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterForget(org.springframework.data.redis.connection.RedisClusterNode) */ @Override - public void clusterForget(final RedisClusterNode node) { + public void clusterForget(RedisClusterNode node) { List nodes = new ArrayList<>(clusterGetNodes()); - final RedisClusterNode nodeToRemove = topologyProvider.getTopology().lookup(node); + RedisClusterNode nodeToRemove = topologyProvider.getTopology().lookup(node); nodes.remove(nodeToRemove); this.clusterCommandExecutor.executeCommandAsyncOnNodes( @@ -366,7 +366,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterMeet(org.springframework.data.redis.connection.RedisClusterNode) */ @Override - public void clusterMeet(final RedisClusterNode node) { + public void clusterMeet(RedisClusterNode node) { Assert.notNull(node, "Cluster node must not be null for CLUSTER MEET command!"); Assert.hasText(node.getHost(), "Node to meet cluster must have a host!"); @@ -381,13 +381,13 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterSetSlot(org.springframework.data.redis.connection.RedisClusterNode, int, org.springframework.data.redis.connection.RedisClusterCommands.AddSlots) */ @Override - public void clusterSetSlot(final RedisClusterNode node, final int slot, final AddSlots mode) { + public void clusterSetSlot(RedisClusterNode node, int slot, AddSlots mode) { Assert.notNull(node, "Node must not be null."); Assert.notNull(mode, "AddSlots mode must not be null."); - final RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(node); - final String nodeId = nodeToUse.getId(); + RedisClusterNode nodeToUse = topologyProvider.getTopology().lookup(node); + String nodeId = nodeToUse.getId(); clusterCommandExecutor.executeCommandOnSingleNode((LettuceClusterCommandCallback) client -> { switch (mode) { @@ -438,9 +438,9 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau * @see org.springframework.data.redis.connection.RedisClusterCommands#clusterReplicate(org.springframework.data.redis.connection.RedisClusterNode, org.springframework.data.redis.connection.RedisClusterNode) */ @Override - public void clusterReplicate(final RedisClusterNode master, RedisClusterNode slave) { + public void clusterReplicate(RedisClusterNode master, RedisClusterNode slave) { - final RedisClusterNode masterNode = topologyProvider.getTopology().lookup(master); + RedisClusterNode masterNode = topologyProvider.getTopology().lookup(master); clusterCommandExecutor.executeCommandOnSingleNode( (LettuceClusterCommandCallback) client -> client.clusterReplicate(masterNode.getId()), slave); } @@ -479,7 +479,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau * @see org.springframework.data.redis.connection.RedisClusterConnection#keys(org.springframework.data.redis.connection.RedisClusterNode, byte[]) */ @Override - public Set keys(RedisClusterNode node, final byte[] pattern) { + public Set keys(RedisClusterNode node, byte[] pattern) { return doGetClusterKeyCommands().keys(node, pattern); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java index fcb5aba06..9c9df3883 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterKeyCommands.java @@ -28,6 +28,7 @@ import org.springframework.data.redis.connection.SortParameters; import org.springframework.data.redis.connection.lettuce.LettuceClusterConnection.LettuceClusterCommandCallback; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -88,7 +89,7 @@ class LettuceClusterKeyCommands extends LettuceKeyCommands { * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#keys(byte[]) */ @Override - public Set keys(final byte[] pattern) { + public Set keys(byte[] pattern) { Assert.notNull(pattern, "Pattern must not be null!"); @@ -109,19 +110,22 @@ class LettuceClusterKeyCommands extends LettuceKeyCommands { * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#rename(byte[], byte[]) */ @Override - public void rename(byte[] oldName, byte[] newName) { + public void rename(byte[] sourceKey, byte[] targetKey) { - if (ClusterSlotHashUtil.isSameSlotForAllKeys(oldName, newName)) { - super.rename(oldName, newName); + Assert.notNull(sourceKey, "Source key must not be null!"); + Assert.notNull(targetKey, "Target key must not be null!"); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(sourceKey, targetKey)) { + super.rename(sourceKey, targetKey); return; } - byte[] value = dump(oldName); + byte[] value = dump(sourceKey); if (value != null && value.length > 0) { - restore(newName, 0, value); - del(oldName); + restore(targetKey, 0, value); + del(sourceKey); } } @@ -130,18 +134,21 @@ class LettuceClusterKeyCommands extends LettuceKeyCommands { * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#renameNX(byte[], byte[]) */ @Override - public Boolean renameNX(byte[] oldName, byte[] newName) { + public Boolean renameNX(byte[] sourceKey, byte[] targetKey) { - if (ClusterSlotHashUtil.isSameSlotForAllKeys(oldName, newName)) { - return super.renameNX(oldName, newName); + Assert.notNull(sourceKey, "Source key must not be null!"); + Assert.notNull(targetKey, "Target key must not be null!"); + + if (ClusterSlotHashUtil.isSameSlotForAllKeys(sourceKey, targetKey)) { + return super.renameNX(sourceKey, targetKey); } - byte[] value = dump(oldName); + byte[] value = dump(sourceKey); - if (value != null && value.length > 0 && !exists(newName)) { + if (value != null && value.length > 0 && !exists(targetKey)) { - restore(newName, 0, value); - del(oldName); + restore(targetKey, 0, value); + del(sourceKey); return Boolean.TRUE; } return Boolean.FALSE; @@ -156,23 +163,11 @@ class LettuceClusterKeyCommands extends LettuceKeyCommands { throw new UnsupportedOperationException("MOVE not supported in CLUSTER mode!"); } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#del(byte[][]) - */ - @Override - public Long del(byte[]... keys) { - - Assert.noNullElements(keys, "Keys must not be null or contain null key!"); - - // Routing for mget is handled by lettuce. - return super.del(keys); - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisClusterConnection#randomKey(org.springframework.data.redis.connection.RedisClusterNode) */ + @Nullable public byte[] randomKey(RedisClusterNode node) { return connection.getClusterCommandExecutor() @@ -184,7 +179,10 @@ class LettuceClusterKeyCommands extends LettuceKeyCommands { * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisClusterConnection#keys(org.springframework.data.redis.connection.RedisClusterNode, byte[]) */ - public Set keys(RedisClusterNode node, final byte[] pattern) { + @Nullable + public Set keys(RedisClusterNode node, byte[] pattern) { + + Assert.notNull(pattern, "Pattern must not be null!"); return LettuceConverters.toBytesSet(connection.getClusterCommandExecutor() .executeCommandOnSingleNode((LettuceClusterCommandCallback>) client -> client.keys(pattern), node) @@ -198,6 +196,8 @@ class LettuceClusterKeyCommands extends LettuceKeyCommands { @Override public Long sort(byte[] key, SortParameters params, byte[] storeKey) { + Assert.notNull(key, "Key must not be null!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(key, storeKey)) { return super.sort(key, params, storeKey); } @@ -220,5 +220,4 @@ class LettuceClusterKeyCommands extends LettuceKeyCommands { } return 0L; } - } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterListCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterListCommands.java index 8303d5128..7714985f6 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterListCommands.java @@ -23,6 +23,7 @@ import java.util.List; import org.springframework.data.redis.connection.ClusterSlotHashUtil; import org.springframework.data.redis.connection.lettuce.LettuceClusterConnection.LettuceMultiKeyClusterCommandCallback; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; /** @@ -45,7 +46,10 @@ class LettuceClusterListCommands extends LettuceListCommands { * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#bLPop(int, byte[][]) */ @Override - public List bLPop(final int timeout, byte[]... keys) { + public List bLPop(int timeout, byte[]... keys) { + + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { return super.bLPop(timeout, keys); @@ -69,7 +73,10 @@ class LettuceClusterListCommands extends LettuceListCommands { * @see org.springframework.data.redis.connection.lettuce.LettuceConnection#bRPop(int, byte[][]) */ @Override - public List bRPop(final int timeout, byte[]... keys) { + public List bRPop(int timeout, byte[]... keys) { + + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { return super.bRPop(timeout, keys); @@ -95,6 +102,9 @@ class LettuceClusterListCommands extends LettuceListCommands { @Override public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(dstKey, "Destination key must not be null!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { return super.rPopLPush(srcKey, dstKey); } @@ -111,6 +121,9 @@ class LettuceClusterListCommands extends LettuceListCommands { @Override public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(dstKey, "Destination key must not be null!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, dstKey)) { return super.bRPopLPush(timeout, srcKey, dstKey); } 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 0a518b74f..65217f9b7 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 @@ -185,7 +185,9 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi * @see org.springframework.data.redis.connection.lettuce.LettuceServerCommands#info(java.lang.String) */ @Override - public Properties info(final String section) { + public Properties info(String section) { + + Assert.hasText(section, "Section must not be null or empty!"); Properties infos = new Properties(); List> nodeResults = executeCommandOnAllNodes( @@ -205,7 +207,10 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi * @see org.springframework.data.redis.connection.RedisClusterServerCommands#info(org.springframework.data.redis.connection.RedisClusterNode, java.lang.String) */ @Override - public Properties info(RedisClusterNode node, final String section) { + public Properties info(RedisClusterNode node, String section) { + + Assert.hasText(section, "Section must not be null or empty!"); + return LettuceConverters.toProperties(executeCommandOnSingleNode(client -> client.info(section), node).getValue()); } @@ -227,7 +232,9 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi * @see org.springframework.data.redis.connection.lettuce.LettuceServerCommands#getConfig(java.lang.String) */ @Override - public Properties getConfig(final String pattern) { + public Properties getConfig(String pattern) { + + Assert.hasText(pattern, "Pattern must not be null or empty!"); List>> mapResult = executeCommandOnAllNodes(client -> client.configGet(pattern)) .getResults(); @@ -248,7 +255,10 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi * @see org.springframework.data.redis.connection.RedisClusterServerCommands#getConfig(org.springframework.data.redis.connection.RedisClusterNode, java.lang.String) */ @Override - public Properties getConfig(RedisClusterNode node, final String pattern) { + public Properties getConfig(RedisClusterNode node, String pattern) { + + Assert.hasText(pattern, "Pattern must not be null or empty!"); + return executeCommandOnSingleNode(client -> Converters.toProperties(client.configGet(pattern)), node).getValue(); } @@ -257,7 +267,11 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi * @see org.springframework.data.redis.connection.lettuce.LettuceServerCommands#setConfig(java.lang.String, java.lang.String) */ @Override - public void setConfig(final String param, final String value) { + public void setConfig(String param, String value) { + + Assert.hasText(param, "Parameter must not be null or empty!"); + Assert.hasText(value, "Value must not be null or empty!"); + executeCommandOnAllNodes(client -> client.configSet(param, value)); } @@ -266,7 +280,11 @@ class LettuceClusterServerCommands extends LettuceServerCommands implements Redi * @see org.springframework.data.redis.connection.RedisClusterServerCommands#setConfig(org.springframework.data.redis.connection.RedisClusterNode, java.lang.String, java.lang.String) */ @Override - public void setConfig(RedisClusterNode node, final String param, final String value) { + public void setConfig(RedisClusterNode node, String param, String value) { + + Assert.hasText(param, "Parameter must not be null or empty!"); + Assert.hasText(value, "Value must not be null or empty!"); + executeCommandOnSingleNode(client -> client.configSet(param, value), node); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterSetCommands.java index a1fe2fb66..ad800a410 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterSetCommands.java @@ -26,6 +26,7 @@ import org.springframework.data.redis.connection.ClusterSlotHashUtil; import org.springframework.data.redis.connection.lettuce.LettuceClusterConnection.LettuceMultiKeyClusterCommandCallback; import org.springframework.data.redis.connection.util.ByteArraySet; import org.springframework.data.redis.util.ByteUtils; +import org.springframework.util.Assert; /** * @author Christoph Strobl @@ -49,6 +50,10 @@ class LettuceClusterSetCommands extends LettuceSetCommands { @Override public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(srcKey, destKey)) { return super.sMove(srcKey, destKey, value); } @@ -68,6 +73,9 @@ class LettuceClusterSetCommands extends LettuceSetCommands { @Override public Set sInter(byte[]... keys) { + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { return super.sInter(keys); } @@ -105,6 +113,10 @@ class LettuceClusterSetCommands extends LettuceSetCommands { @Override public Long sInterStore(byte[] destKey, byte[]... keys) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -125,6 +137,9 @@ class LettuceClusterSetCommands extends LettuceSetCommands { @Override public Set sUnion(byte[]... keys) { + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { return super.sUnion(keys); } @@ -153,6 +168,10 @@ class LettuceClusterSetCommands extends LettuceSetCommands { @Override public Long sUnionStore(byte[] destKey, byte[]... keys) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { @@ -173,6 +192,9 @@ class LettuceClusterSetCommands extends LettuceSetCommands { @Override public Set sDiff(byte[]... keys) { + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { return super.sDiff(keys); } @@ -204,6 +226,10 @@ class LettuceClusterSetCommands extends LettuceSetCommands { @Override public Long sDiffStore(byte[] destKey, byte[]... keys) { + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + byte[][] allKeys = ByteUtils.mergeArrays(destKey, keys); if (ClusterSlotHashUtil.isSameSlotForAllKeys(allKeys)) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java index ed0343864..108def426 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClusterStringCommands.java @@ -18,6 +18,7 @@ package org.springframework.data.redis.connection.lettuce; import java.util.Map; import org.springframework.data.redis.connection.ClusterSlotHashUtil; +import org.springframework.util.Assert; /** * @author Christoph Strobl @@ -37,6 +38,8 @@ class LettuceClusterStringCommands extends LettuceStringCommands { @Override public Boolean mSetNX(Map tuples) { + Assert.notNull(tuples, "Tuples must not be null!"); + if (ClusterSlotHashUtil.isSameSlotForAllKeys(tuples.keySet().toArray(new byte[tuples.keySet().size()][]))) { return super.mSetNX(tuples); } 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 7a0d412f4..dd776a2bd 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,7 +95,7 @@ public class LettuceConnection extends AbstractRedisConnection { private int dbIndex; private final LettuceConnectionProvider connectionProvider; - private final StatefulConnection asyncSharedConn; + private final @Nullable StatefulConnection asyncSharedConn; private @Nullable StatefulConnection asyncDedicatedConn; private final long timeout; @@ -105,7 +105,7 @@ public class LettuceConnection extends AbstractRedisConnection { private boolean isMulti = false; private boolean isPipelined = false; private @Nullable List ppline; - private Queue> txResults = new LinkedList<>(); + private final Queue> txResults = new LinkedList<>(); private volatile @Nullable LettuceSubscription subscription; /** flag indicating whether the connection needs to be dropped or not */ private boolean convertPipelineAndTxResults = true; @@ -129,7 +129,7 @@ public class LettuceConnection extends AbstractRedisConnection { } return resultHolder.getOutput().get(); } catch (Exception e) { - throw EXCEPTION_TRANSLATION.translate(e); + throw LettuceConnection.this.convertLettuceAccessException(e); } } } @@ -239,7 +239,8 @@ public class LettuceConnection extends AbstractRedisConnection { * @param timeout The connection timeout (in milliseconds) * @param client The {@link RedisClient} to use when making pub/sub, blocking, and tx connections */ - public LettuceConnection(StatefulRedisConnection sharedConnection, long timeout, RedisClient client) { + public LettuceConnection(@Nullable StatefulRedisConnection sharedConnection, long timeout, + RedisClient client) { this(sharedConnection, timeout, client, null); } @@ -255,8 +256,8 @@ public class LettuceConnection extends AbstractRedisConnection { * {@link #LettuceConnection(StatefulRedisConnection, LettuceConnectionProvider, long, int)} */ @Deprecated - public LettuceConnection(StatefulRedisConnection sharedConnection, long timeout, RedisClient client, - LettucePool pool) { + public LettuceConnection(@Nullable StatefulRedisConnection sharedConnection, long timeout, + RedisClient client, @Nullable LettucePool pool) { this(sharedConnection, timeout, client, pool, 0); } @@ -273,8 +274,8 @@ public class LettuceConnection extends AbstractRedisConnection { * {@link #LettuceConnection(StatefulRedisConnection, LettuceConnectionProvider, long, int)} */ @Deprecated - public LettuceConnection(StatefulRedisConnection sharedConnection, long timeout, - AbstractRedisClient client, LettucePool pool, int defaultDbIndex) { + public LettuceConnection(@Nullable StatefulRedisConnection sharedConnection, long timeout, + @Nullable AbstractRedisClient client, @Nullable LettucePool pool, int defaultDbIndex) { if (pool != null) { this.connectionProvider = new LettucePoolConnectionProvider(pool); @@ -402,6 +403,7 @@ public class LettuceConnection extends AbstractRedisConnection { return new LettuceZSetCommands(this); } + @Nullable @SuppressWarnings({ "rawtypes", "unchecked" }) private Object await(RedisFuture cmd) { @@ -425,8 +427,9 @@ public class LettuceConnection extends AbstractRedisConnection { * @param args Possible command arguments (may be {@literal null}) * @return execution result. */ + @Nullable @SuppressWarnings({ "rawtypes", "unchecked" }) - public Object execute(String command, CommandOutput commandOutputTypeHint, byte[]... args) { + public Object execute(String command, @Nullable CommandOutput commandOutputTypeHint, byte[]... args) { Assert.hasText(command, "a valid command needs to be specified"); try { @@ -461,6 +464,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public void close() throws DataAccessException { super.close(); @@ -489,22 +493,27 @@ public class LettuceConnection extends AbstractRedisConnection { this.dbIndex = defaultDbIndex; } + @Override public boolean isClosed() { return isClosed && !isSubscribed(); } + @Override public RedisClusterAsyncCommands getNativeConnection() { return (subscription != null ? subscription.pubsub.async() : getAsyncConnection()); } + @Override public boolean isQueueing() { return isMulti; } + @Override public boolean isPipelined() { return isPipelined; } + @Override public void openPipeline() { if (!isPipelined) { isPipelined = true; @@ -512,6 +521,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public List closePipeline() { if (isPipelined) { @@ -593,6 +603,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public String ping() { try { if (isPipelined()) { @@ -609,6 +620,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public void discard() { isMulti = false; try { @@ -624,6 +636,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public List exec() { isMulti = false; @@ -632,7 +645,7 @@ public class LettuceConnection extends AbstractRedisConnection { RedisFuture exec = ((RedisAsyncCommands) getAsyncDedicatedConnection()).exec(); LettuceTransactionResultConverter resultConverter = new LettuceTransactionResultConverter( - new LinkedList>(txResults), LettuceConverters.exceptionConverter()); + new LinkedList<>(txResults), LettuceConverters.exceptionConverter()); pipeline(new LettuceResult(exec, source -> resultConverter.convert(LettuceConverters.transactionResultUnwrapper().convert(source)))); @@ -651,6 +664,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public void multi() { if (isQueueing()) { return; @@ -667,6 +681,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public void select(int dbIndex) { if (asyncSharedConn != null) { @@ -689,6 +704,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public void unwatch() { try { if (isPipelined()) { @@ -705,6 +721,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public void watch(byte[]... keys) { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -728,6 +745,7 @@ public class LettuceConnection extends AbstractRedisConnection { // Pub/Sub functionality // + @Override public Long publish(byte[] channel, byte[] message) { try { if (isPipelined()) { @@ -744,14 +762,17 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public Subscription getSubscription() { return subscription; } + @Override public boolean isSubscribed() { return (subscription != null && subscription.isAlive()); } + @Override public void pSubscribe(MessageListener listener, byte[]... patterns) { checkSubscription(); @@ -769,6 +790,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } + @Override public void subscribe(MessageListener listener, byte[]... channels) { checkSubscription(); @@ -918,7 +940,9 @@ public class LettuceConnection extends AbstractRedisConnection { return io.lettuce.core.ScanCursor.of(Long.toString(cursorId)); } - ScanArgs getScanArgs(ScanOptions options) { + @Nullable + ScanArgs getScanArgs(@Nullable ScanOptions options) { + if (options == null) { return null; } @@ -943,7 +967,7 @@ public class LettuceConnection extends AbstractRedisConnection { } } - private void validateCommand(CommandType cmd, byte[]... args) { + private void validateCommand(CommandType cmd, @Nullable byte[]... args) { RedisCommand redisCommand = RedisCommand.failsafeCommandLookup(cmd.name()); if (!RedisCommand.UNKNOWN.equals(redisCommand) && redisCommand.requiresArguments()) { @@ -958,10 +982,6 @@ public class LettuceConnection extends AbstractRedisConnection { @Override protected boolean isActive(RedisNode node) { - if (node == null) { - return false; - } - StatefulRedisSentinelConnection connection = null; try { connection = getConnection(node); @@ -992,8 +1012,8 @@ public class LettuceConnection extends AbstractRedisConnection { @SuppressWarnings("unchecked") private StatefulRedisSentinelConnection getConnection(RedisNode sentinel) { - return (StatefulRedisSentinelConnection) ((TargetAware) connectionProvider) - .getConnection(StatefulRedisSentinelConnection.class, getRedisURI(sentinel)); + return ((TargetAware) connectionProvider).getConnection(StatefulRedisSentinelConnection.class, + getRedisURI(sentinel)); } LettuceConnectionProvider getConnectionProvider() { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionProvider.java index afe74f986..f38fb0590 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionProvider.java @@ -46,7 +46,6 @@ public interface LettuceConnectionProvider { * @return the requested connection. Must be {@link #release(StatefulConnection) released} if the connection is no * longer in use. */ - @SuppressWarnings("rawtypes") > T getConnection(Class connectionType); /** @@ -72,7 +71,6 @@ public interface LettuceConnectionProvider { * @param redisURI must not be {@literal null}. * @return the requested connection. */ - @SuppressWarnings("rawtypes") > T getConnection(Class connectionType, RedisURI redisURI); } } 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 80bd3cb41..395c2fa3d 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 @@ -33,12 +33,17 @@ import org.springframework.data.redis.RedisSystemException; /** * Converts Lettuce Exceptions to {@link DataAccessException}s - * + * * @author Jennifer Hickey * @author Thomas Darimont + * @author Mark Paluch */ public class LettuceExceptionConverter implements Converter { + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object) + */ public DataAccessException convert(Exception ex) { if (ex instanceof ExecutionException || ex instanceof RedisCommandExecutionException) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java index da0c66396..701c3df35 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceGeoCommands.java @@ -20,6 +20,8 @@ import io.lettuce.core.GeoCoordinates; import io.lettuce.core.GeoWithin; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.ArrayList; import java.util.Collection; @@ -40,19 +42,18 @@ import org.springframework.data.redis.connection.RedisGeoCommands; import org.springframework.data.redis.connection.convert.ListConverter; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** * @author Christoph Strobl + * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class LettuceGeoCommands implements RedisGeoCommands { - private final LettuceConnection connection; - - public LettuceGeoCommands(LettuceConnection connection) { - this.connection = connection; - } + private final @NonNull LettuceConnection connection; /* * (non-Javadoc) @@ -80,33 +81,6 @@ class LettuceGeoCommands implements RedisGeoCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation) - */ - @Override - public Long geoAdd(byte[] key, GeoLocation location) { - - Assert.notNull(key, "Key must not be null!"); - Assert.notNull(location, "Location must not be null!"); - - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().geoadd(key, location.getPoint().getX(), - location.getPoint().getY(), location.getName()))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult( - getConnection().geoadd(key, location.getPoint().getX(), location.getPoint().getY(), location.getName()))); - return null; - } - return getConnection().geoadd(key, location.getPoint().getX(), location.getPoint().getY(), location.getName()); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisGeoCommands#geoAdd(byte[], java.util.Map) @@ -149,6 +123,7 @@ class LettuceGeoCommands implements RedisGeoCommands { return geoAdd(key, values); } + @Nullable private Long geoAdd(byte[] key, Collection values) { try { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java index 81502409d..771d9563c 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHashCommands.java @@ -19,6 +19,8 @@ import io.lettuce.core.MapScanCursor; import io.lettuce.core.ScanArgs; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.List; import java.util.Map; @@ -33,18 +35,17 @@ import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; /** * @author Christoph Strobl + * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class LettuceHashCommands implements RedisHashCommands { - private final LettuceConnection connection; - - public LettuceHashCommands(LettuceConnection connection) { - this.connection = connection; - } + private final @NonNull LettuceConnection connection; /* * (non-Javadoc) @@ -52,6 +53,11 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public Boolean hSet(byte[] key, byte[] field, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hset(key, field, value))); @@ -73,6 +79,11 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hsetnx(key, field, value))); @@ -94,6 +105,10 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public Long hDel(byte[] key, byte[]... fields) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(fields, "Fields must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hdel(key, fields))); @@ -115,6 +130,10 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public Boolean hExists(byte[] key, byte[] field) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Fields must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hexists(key, field))); @@ -136,6 +155,10 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public byte[] hGet(byte[] key, byte[] field) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hget(key, field))); @@ -157,6 +180,9 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public Map hGetAll(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hgetall(key))); @@ -178,6 +204,10 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public Long hIncrBy(byte[] key, byte[] field, long delta) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hincrby(key, field, delta))); @@ -199,6 +229,10 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public Double hIncrBy(byte[] key, byte[] field, double delta) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(field, "Field must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hincrbyfloat(key, field, delta))); @@ -220,6 +254,9 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public Set hKeys(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hkeys(key), LettuceConverters.bytesListToBytesSet())); @@ -241,6 +278,9 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public Long hLen(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hlen(key))); @@ -262,6 +302,10 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public List hMGet(byte[] key, byte[]... fields) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(fields, "Fields must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hmget(key, fields), @@ -284,17 +328,21 @@ class LettuceHashCommands implements RedisHashCommands { * @see org.springframework.data.redis.connection.RedisHashCommands#hMSet(byte[], java.util.Map) */ @Override - public void hMSet(byte[] key, Map tuple) { + public void hMSet(byte[] key, Map hashes) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(hashes, "Hashes must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().hmset(key, tuple))); + pipeline(connection.newLettuceStatusResult(getAsyncConnection().hmset(key, hashes))); return; } if (isQueueing()) { - transaction(connection.newLettuceTxStatusResult(getConnection().hmset(key, tuple))); + transaction(connection.newLettuceTxStatusResult(getConnection().hmset(key, hashes))); return; } - getConnection().hmset(key, tuple); + getConnection().hmset(key, hashes); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -306,6 +354,9 @@ class LettuceHashCommands implements RedisHashCommands { */ @Override public List hVals(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().hvals(key))); @@ -338,6 +389,8 @@ class LettuceHashCommands implements RedisHashCommands { */ public Cursor> hScan(byte[] key, long cursorId, ScanOptions options) { + Assert.notNull(key, "Key must not be null!"); + return new KeyBoundCursor>(key, cursorId, options) { @Override @@ -357,6 +410,7 @@ class LettuceHashCommands implements RedisHashCommands { return new ScanIteration<>(Long.valueOf(nextCursorId), values.entrySet()); } + @Override protected void doClose() { LettuceHashCommands.this.connection.close(); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java index 1b0a55539..de15d88ca 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceHyperLogLogCommands.java @@ -19,6 +19,8 @@ import io.lettuce.core.api.async.RedisHLLAsyncCommands; import io.lettuce.core.api.sync.RedisHLLCommands; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisHyperLogLogCommands; @@ -28,15 +30,13 @@ import org.springframework.util.Assert; /** * @author Christoph Strobl + * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class LettuceHyperLogLogCommands implements RedisHyperLogLogCommands { - private final LettuceConnection connection; - - public LettuceHyperLogLogCommands(LettuceConnection connection) { - this.connection = connection; - } + private final @NonNull LettuceConnection connection; /* * (non-Javadoc) @@ -77,6 +77,7 @@ class LettuceHyperLogLogCommands implements RedisHyperLogLogCommands { Assert.notEmpty(keys, "PFCOUNT requires at least one non 'null' key."); Assert.noNullElements(keys, "Keys for PFCOUNT must not contain 'null'."); + try { if (isPipelined()) { RedisHLLAsyncCommands asyncConnection = getAsyncConnection(); @@ -104,8 +105,9 @@ class LettuceHyperLogLogCommands implements RedisHyperLogLogCommands { @Override public void pfMerge(byte[] destinationKey, byte[]... sourceKeys) { - Assert.notEmpty(sourceKeys, "PFMERGE requires at least one non 'null' source key."); - Assert.noNullElements(sourceKeys, "source key for PFMERGE must not contain 'null'."); + Assert.notNull(destinationKey, "Destination key must not be null"); + Assert.notNull(sourceKeys, "Source keys must not be null"); + Assert.noNullElements(sourceKeys, "Keys for PFMERGE must not contain 'null'."); try { if (isPipelined()) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java index 85e047441..9d04f10d6 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceKeyCommands.java @@ -20,6 +20,8 @@ import io.lettuce.core.ScanArgs; import io.lettuce.core.SortArgs; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.List; import java.util.Set; @@ -40,80 +42,13 @@ import org.springframework.util.Assert; /** * @author Christoph Strobl + * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class LettuceKeyCommands implements RedisKeyCommands { - private final LettuceConnection connection; - - public LettuceKeyCommands(LettuceConnection connection) { - this.connection = connection; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#dump(byte[]) - */ - @Override - public byte[] dump(byte[] key) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().dump(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().dump(key))); - return null; - } - return getConnection().dump(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#restore(byte[], long, byte[]) - */ - @Override - public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().restore(key, ttlInMillis, serializedValue))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceTxStatusResult(getConnection().restore(key, ttlInMillis, serializedValue))); - return; - } - getConnection().restore(key, ttlInMillis, serializedValue); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#keys(byte[]) - */ - @Override - public Set keys(byte[] pattern) { - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceTxResult(getConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().keys(pattern)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } + private final @NonNull LettuceConnection connection; /* * (non-Javadoc) @@ -121,6 +56,9 @@ class LettuceKeyCommands implements RedisKeyCommands { */ @Override public Boolean exists(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().exists(new byte[][] { key }), @@ -138,12 +76,216 @@ class LettuceKeyCommands implements RedisKeyCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#del(byte[][]) + */ + @Override + public Long del(byte[]... keys) { + + Assert.noNullElements(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().del(keys))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().del(keys))); + return null; + } + return getConnection().del(keys); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#type(byte[]) + */ + @Override + public DataType type(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().type(key), LettuceConverters.stringToDataType())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().type(key), LettuceConverters.stringToDataType())); + return null; + } + return LettuceConverters.toDataType(getConnection().type(key)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#keys(byte[]) + */ + @Override + public Set keys(byte[] pattern) { + + Assert.notNull(pattern, "Pattern must not be null!"); + + try { + if (isPipelined()) { + pipeline( + connection.newLettuceResult(getAsyncConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); + return null; + } + if (isQueueing()) { + transaction( + connection.newLettuceTxResult(getConnection().keys(pattern), LettuceConverters.bytesListToBytesSet())); + return null; + } + return LettuceConverters.toBytesSet(getConnection().keys(pattern)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /** + * @since 1.4 + * @return + */ + public Cursor scan() { + return scan(0, ScanOptions.NONE); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#scan(org.springframework.data.redis.core.ScanOptions) + */ + @Override + public Cursor scan(ScanOptions options) { + return scan(0, options != null ? options : ScanOptions.NONE); + } + + /** + * @since 1.4 + * @param cursorId + * @param options + * @return + */ + public Cursor scan(long cursorId, ScanOptions options) { + + return new ScanCursor(cursorId, options) { + + @SuppressWarnings("unchecked") + @Override + protected ScanIteration doScan(long cursorId, ScanOptions options) { + + if (isQueueing() || isPipelined()) { + throw new UnsupportedOperationException("'SCAN' cannot be called in pipeline / transaction mode."); + } + + io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); + ScanArgs scanArgs = connection.getScanArgs(options); + + KeyScanCursor keyScanCursor = getConnection().scan(scanCursor, scanArgs); + String nextCursorId = keyScanCursor.getCursor(); + + List keys = keyScanCursor.getKeys(); + + return new ScanIteration<>(Long.valueOf(nextCursorId), (keys)); + } + + @Override + protected void doClose() { + LettuceKeyCommands.this.connection.close(); + } + + }.open(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#randomKey() + */ + @Override + public byte[] randomKey() { + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().randomkey())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().randomkey())); + return null; + } + return getConnection().randomkey(); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#rename(byte[], byte[]) + */ + @Override + public void rename(byte[] sourceKey, byte[] targetKey) { + + Assert.notNull(sourceKey, "Source key must not be null!"); + Assert.notNull(targetKey, "Target key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().rename(sourceKey, targetKey))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().rename(sourceKey, targetKey))); + return; + } + getConnection().rename(sourceKey, targetKey); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#renameNX(byte[], byte[]) + */ + @Override + public Boolean renameNX(byte[] sourceKey, byte[] targetKey) { + + Assert.notNull(sourceKey, "Source key must not be null!"); + Assert.notNull(targetKey, "Target key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().renamenx(sourceKey, targetKey))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().renamenx(sourceKey, targetKey))); + return null; + } + return (getConnection().renamenx(sourceKey, targetKey)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisKeyCommands#expire(byte[], long) */ @Override public Boolean expire(byte[] key, long seconds) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().expire(key, seconds))); @@ -159,33 +301,15 @@ class LettuceKeyCommands implements RedisKeyCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#expireAt(byte[], long) - */ - @Override - public Boolean expireAt(byte[] key, long unixTime) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().expireat(key, unixTime))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().expireat(key, unixTime))); - return null; - } - return getConnection().expireat(key, unixTime); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpire(byte[], long) */ @Override public Boolean pExpire(byte[] key, long millis) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().pexpire(key, millis))); @@ -201,12 +325,39 @@ class LettuceKeyCommands implements RedisKeyCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#expireAt(byte[], long) + */ + @Override + public Boolean expireAt(byte[] key, long unixTime) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().expireat(key, unixTime))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().expireat(key, unixTime))); + return null; + } + return getConnection().expireat(key, unixTime); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisKeyCommands#pExpireAt(byte[], long) */ @Override public Boolean pExpireAt(byte[] key, long unixTimeInMillis) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().pexpireat(key, unixTimeInMillis))); @@ -222,6 +373,104 @@ class LettuceKeyCommands implements RedisKeyCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#persist(byte[]) + */ + @Override + public Boolean persist(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().persist(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().persist(key))); + return null; + } + return getConnection().persist(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#move(byte[], int) + */ + @Override + public Boolean move(byte[] key, int dbIndex) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().move(key, dbIndex))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().move(key, dbIndex))); + return null; + } + return getConnection().move(key, dbIndex); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[]) + */ + @Override + public Long ttl(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().ttl(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().ttl(key))); + return null; + } + + return getConnection().ttl(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[], java.util.concurrent.TimeUnit) + */ + @Override + public Long ttl(byte[] key, TimeUnit timeUnit) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().ttl(key), Converters.secondsToTimeUnit(timeUnit))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().ttl(key), Converters.secondsToTimeUnit(timeUnit))); + return null; + } + + return Converters.secondsToTimeUnit(getConnection().ttl(key), timeUnit); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisKeyCommands#pTtl(byte[]) @@ -274,27 +523,6 @@ class LettuceKeyCommands implements RedisKeyCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#del(byte[][]) - */ - @Override - public Long del(byte[]... keys) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().del(keys))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().del(keys))); - return null; - } - return getConnection().del(keys); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisKeyCommands#sort(byte[], org.springframework.data.redis.connection.SortParameters) @@ -302,6 +530,8 @@ class LettuceKeyCommands implements RedisKeyCommands { @Override public List sort(byte[] key, SortParameters params) { + Assert.notNull(key, "Key must not be null!"); + SortArgs args = LettuceConverters.toSortArgs(params); try { @@ -326,6 +556,8 @@ class LettuceKeyCommands implements RedisKeyCommands { @Override public Long sort(byte[] key, SortParameters params, byte[] sortKey) { + Assert.notNull(key, "Key must not be null!"); + SortArgs args = LettuceConverters.toSortArgs(params); try { @@ -345,129 +577,23 @@ class LettuceKeyCommands implements RedisKeyCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#persist(byte[]) + * @see org.springframework.data.redis.connection.RedisKeyCommands#dump(byte[]) */ @Override - public Boolean persist(byte[] key) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().persist(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().persist(key))); - return null; - } - return getConnection().persist(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#move(byte[], int) - */ - @Override - public Boolean move(byte[] key, int dbIndex) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().move(key, dbIndex))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().move(key, dbIndex))); - return null; - } - return getConnection().move(key, dbIndex); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#randomKey() - */ - @Override - public byte[] randomKey() { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().randomkey())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().randomkey())); - return null; - } - return getConnection().randomkey(); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#rename(byte[], byte[]) - */ - @Override - public void rename(byte[] oldName, byte[] newName) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().rename(oldName, newName))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceTxStatusResult(getConnection().rename(oldName, newName))); - return; - } - getConnection().rename(oldName, newName); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#renameNX(byte[], byte[]) - */ - @Override - public Boolean renameNX(byte[] oldName, byte[] newName) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().renamenx(oldName, newName))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().renamenx(oldName, newName))); - return null; - } - return (getConnection().renamenx(oldName, newName)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[]) - */ - @Override - public Long ttl(byte[] key) { + public byte[] dump(byte[] key) { Assert.notNull(key, "Key must not be null!"); try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().ttl(key))); + pipeline(connection.newLettuceResult(getAsyncConnection().dump(key))); return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().ttl(key))); + transaction(connection.newLettuceTxResult(getConnection().dump(key))); return null; } - - return getConnection().ttl(key); + return getConnection().dump(key); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -475,104 +601,29 @@ class LettuceKeyCommands implements RedisKeyCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#ttl(byte[], java.util.concurrent.TimeUnit) + * @see org.springframework.data.redis.connection.RedisKeyCommands#restore(byte[], long, byte[]) */ @Override - public Long ttl(byte[] key, TimeUnit timeUnit) { + public void restore(byte[] key, long ttlInMillis, byte[] serializedValue) { Assert.notNull(key, "Key must not be null!"); + Assert.notNull(serializedValue, "Serialized value must not be null!"); try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().ttl(key), Converters.secondsToTimeUnit(timeUnit))); - return null; + pipeline(connection.newLettuceStatusResult(getAsyncConnection().restore(key, ttlInMillis, serializedValue))); + return; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().ttl(key), Converters.secondsToTimeUnit(timeUnit))); - return null; + transaction(connection.newLettuceTxStatusResult(getConnection().restore(key, ttlInMillis, serializedValue))); + return; } - - return Converters.secondsToTimeUnit(getConnection().ttl(key), timeUnit); + getConnection().restore(key, ttlInMillis, serializedValue); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#type(byte[]) - */ - @Override - public DataType type(byte[] key) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().type(key), LettuceConverters.stringToDataType())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().type(key), LettuceConverters.stringToDataType())); - return null; - } - return LettuceConverters.toDataType(getConnection().type(key)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /** - * @since 1.4 - * @return - */ - public Cursor scan() { - return scan(0, ScanOptions.NONE); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisKeyCommands#scan(org.springframework.data.redis.core.ScanOptions) - */ - @Override - public Cursor scan(ScanOptions options) { - return scan(0, options != null ? options : ScanOptions.NONE); - } - - /** - * @since 1.4 - * @param cursorId - * @param options - * @return - */ - public Cursor scan(long cursorId, ScanOptions options) { - - return new ScanCursor(cursorId, options) { - - @SuppressWarnings("unchecked") - @Override - protected ScanIteration doScan(long cursorId, ScanOptions options) { - - if (isQueueing() || isPipelined()) { - throw new UnsupportedOperationException("'SCAN' cannot be called in pipeline / transaction mode."); - } - - io.lettuce.core.ScanCursor scanCursor = connection.getScanCursor(cursorId); - ScanArgs scanArgs = connection.getScanArgs(options); - - KeyScanCursor keyScanCursor = getConnection().scan(scanCursor, scanArgs); - String nextCursorId = keyScanCursor.getCursor(); - - List keys = keyScanCursor.getKeys(); - - return new ScanIteration<>(Long.valueOf(nextCursorId), (keys)); - } - - protected void doClose() { - LettuceKeyCommands.this.connection.close(); - } - - }.open(); - - } - private boolean isPipelined() { return connection.isPipelined(); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java index 95bbbf659..79f84f2fc 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceListCommands.java @@ -17,6 +17,8 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.List; @@ -24,39 +26,17 @@ import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisListCommands; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.util.Assert; /** * @author Christoph Strobl + * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class LettuceListCommands implements RedisListCommands { - private final LettuceConnection connection; - - public LettuceListCommands(LettuceConnection connection) { - this.connection = connection; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lPush(byte[], byte[][]) - */ - @Override - public Long lPush(byte[] key, byte[]... values) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lpush(key, values))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().lpush(key, values))); - return null; - } - return getConnection().lpush(key, values); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } + private final @NonNull LettuceConnection connection; /* * (non-Javadoc) @@ -64,6 +44,9 @@ class LettuceListCommands implements RedisListCommands { */ @Override public Long rPush(byte[] key, byte[]... values) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().rpush(key, values))); @@ -79,12 +62,312 @@ class LettuceListCommands implements RedisListCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPush(byte[], byte[][]) + */ + @Override + public Long lPush(byte[] key, byte[]... values) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lpush(key, values))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lpush(key, values))); + return null; + } + return getConnection().lpush(key, values); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPushX(byte[], byte[]) + */ + @Override + public Long rPushX(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().rpushx(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().rpushx(key, value))); + return null; + } + return getConnection().rpushx(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPushX(byte[], byte[]) + */ + @Override + public Long lPushX(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lpushx(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lpushx(key, value))); + return null; + } + return getConnection().lpushx(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lLen(byte[]) + */ + @Override + public Long lLen(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().llen(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().llen(key))); + return null; + } + return getConnection().llen(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lRange(byte[], long, long) + */ + @Override + public List lRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lrange(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lrange(key, start, end))); + return null; + } + return getConnection().lrange(key, start, end); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lTrim(byte[], long, long) + */ + @Override + public void lTrim(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().ltrim(key, start, end))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().ltrim(key, start, end))); + return; + } + getConnection().ltrim(key, start, end); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lIndex(byte[], long) + */ + @Override + public byte[] lIndex(byte[] key, long index) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lindex(key, index))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lindex(key, index))); + return null; + } + return getConnection().lindex(key, index); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lInsert(byte[], org.springframework.data.redis.connection.RedisListCommands.Position, byte[], byte[]) + */ + @Override + public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection + .newLettuceResult(getAsyncConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); + return null; + } + if (isQueueing()) { + transaction(connection + .newLettuceTxResult(getConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); + return null; + } + return getConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lSet(byte[], long, byte[]) + */ + @Override + public void lSet(byte[] key, long index, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().lset(key, index, value))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().lset(key, index, value))); + return; + } + getConnection().lset(key, index, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lRem(byte[], long, byte[]) + */ + @Override + public Long lRem(byte[] key, long count, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lrem(key, count, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lrem(key, count, value))); + return null; + } + return getConnection().lrem(key, count, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#lPop(byte[]) + */ + @Override + public byte[] lPop(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().lpop(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().lpop(key))); + return null; + } + return getConnection().lpop(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisListCommands#rPop(byte[]) + */ + @Override + public byte[] rPop(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().rpop(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().rpop(key))); + return null; + } + return getConnection().rpop(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisListCommands#bLPop(int, byte[][]) */ @Override public List bLPop(int timeout, byte[]... keys) { + + Assert.notNull(keys, "Key must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(connection.getAsyncDedicatedConnection().blpop(timeout, keys), @@ -108,6 +391,10 @@ class LettuceListCommands implements RedisListCommands { */ @Override public List bRPop(int timeout, byte[]... keys) { + + Assert.notNull(keys, "Key must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(connection.getAsyncDedicatedConnection().brpop(timeout, keys), @@ -125,203 +412,16 @@ class LettuceListCommands implements RedisListCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lIndex(byte[], long) - */ - @Override - public byte[] lIndex(byte[] key, long index) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lindex(key, index))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().lindex(key, index))); - return null; - } - return getConnection().lindex(key, index); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lInsert(byte[], org.springframework.data.redis.connection.RedisListCommands.Position, byte[], byte[]) - */ - @Override - public Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value) { - try { - if (isPipelined()) { - pipeline(connection - .newLettuceResult(getAsyncConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); - return null; - } - if (isQueueing()) { - transaction(connection - .newLettuceTxResult(getConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value))); - return null; - } - return getConnection().linsert(key, LettuceConverters.toBoolean(where), pivot, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lLen(byte[]) - */ - @Override - public Long lLen(byte[] key) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().llen(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().llen(key))); - return null; - } - return getConnection().llen(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lPop(byte[]) - */ - @Override - public byte[] lPop(byte[] key) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lpop(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().lpop(key))); - return null; - } - return getConnection().lpop(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lRange(byte[], long, long) - */ - @Override - public List lRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lrange(key, start, end))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().lrange(key, start, end))); - return null; - } - return getConnection().lrange(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lRem(byte[], long, byte[]) - */ - @Override - public Long lRem(byte[] key, long count, byte[] value) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lrem(key, count, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().lrem(key, count, value))); - return null; - } - return getConnection().lrem(key, count, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lSet(byte[], long, byte[]) - */ - @Override - public void lSet(byte[] key, long index, byte[] value) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().lset(key, index, value))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceTxStatusResult(getConnection().lset(key, index, value))); - return; - } - getConnection().lset(key, index, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lTrim(byte[], long, long) - */ - @Override - public void lTrim(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().ltrim(key, start, end))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceTxStatusResult(getConnection().ltrim(key, start, end))); - return; - } - getConnection().ltrim(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#rPop(byte[]) - */ - @Override - public byte[] rPop(byte[] key) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().rpop(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().rpop(key))); - return null; - } - return getConnection().rpop(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisListCommands#rPopLPush(byte[], byte[]) */ @Override public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { + + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(dstKey, "Destination key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().rpoplpush(srcKey, dstKey))); @@ -343,6 +443,10 @@ class LettuceListCommands implements RedisListCommands { */ @Override public byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey) { + + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(dstKey, "Destination key must not be null!"); + try { if (isPipelined()) { pipeline( @@ -360,48 +464,6 @@ class LettuceListCommands implements RedisListCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#lPushX(byte[], byte[]) - */ - @Override - public Long lPushX(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().lpushx(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().lpushx(key, value))); - return null; - } - return getConnection().lpushx(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisListCommands#rPushX(byte[], byte[]) - */ - @Override - public Long rPushX(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().rpushx(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().rpushx(key, value))); - return null; - } - return getConnection().rpushx(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - private boolean isPipelined() { return connection.isPipelined(); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterServerCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterServerCommands.java index 35d434db7..b22c9b465 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveClusterServerCommands.java @@ -164,7 +164,7 @@ class LettuceReactiveClusterServerCommands extends LettuceReactiveServerCommands @Override public Mono info(String section) { - Assert.hasText(section, "Section must not be null nor empty!"); + Assert.hasText(section, "Section must not be null or empty!"); return Flux.merge(executeOnAllNodes(redisClusterNode -> info(redisClusterNode, section))) .collect(PropertiesCollector.INSTANCE); @@ -177,7 +177,7 @@ class LettuceReactiveClusterServerCommands extends LettuceReactiveServerCommands @Override public Mono info(RedisClusterNode node, String section) { - Assert.hasText(section, "Section must not be null nor empty!"); + Assert.hasText(section, "Section must not be null or empty!"); return connection.execute(node, c -> c.info(section)) // .map(LettuceConverters::toProperties).next(); @@ -190,7 +190,7 @@ class LettuceReactiveClusterServerCommands extends LettuceReactiveServerCommands @Override public Mono getConfig(String pattern) { - Assert.hasText(pattern, "Pattern must not be null nor empty!"); + Assert.hasText(pattern, "Pattern must not be null or empty!"); return Flux.merge(executeOnAllNodes(node -> getConfig(node, pattern))) // .collect(PropertiesCollector.INSTANCE); @@ -203,7 +203,7 @@ class LettuceReactiveClusterServerCommands extends LettuceReactiveServerCommands @Override public Mono getConfig(RedisClusterNode node, String pattern) { - Assert.hasText(pattern, "Pattern must not be null nor empty!"); + Assert.hasText(pattern, "Pattern must not be null or empty!"); return connection.execute(node, c -> c.configGet(pattern)) // .map(LettuceConverters::toProperties) // @@ -226,8 +226,8 @@ class LettuceReactiveClusterServerCommands extends LettuceReactiveServerCommands @Override public Mono setConfig(RedisClusterNode node, String param, String value) { - Assert.hasText(param, "Param must not be null nor empty!"); - Assert.hasText(value, "Value must not be null nor empty!"); + Assert.hasText(param, "Parameter must not be null or empty!"); + Assert.hasText(value, "Value must not be null or empty!"); return connection.execute(node, c -> c.configSet(param, value)).next(); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveScriptingCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveScriptingCommands.java index 75421f358..13d84f009 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveScriptingCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveScriptingCommands.java @@ -90,7 +90,7 @@ class LettuceReactiveScriptingCommands implements ReactiveScriptingCommands { @Override public Flux scriptExists(List scriptShas) { - Assert.notEmpty(scriptShas, "Script SHAs must not be empty!"); + Assert.notEmpty(scriptShas, "Script digests must not be empty!"); return connection.execute(cmd -> cmd.scriptExists(scriptShas.toArray(new String[scriptShas.size()]))); } @@ -123,7 +123,7 @@ class LettuceReactiveScriptingCommands implements ReactiveScriptingCommands { @Override public Flux evalSha(String scriptSha, ReturnType returnType, int numKeys, ByteBuffer... keysAndArgs) { - Assert.notNull(scriptSha, "Script SHA1 must not be null!"); + Assert.notNull(scriptSha, "Script digest must not be null!"); Assert.notNull(returnType, "ReturnType must not be null!"); Assert.notNull(keysAndArgs, "Keys and args must not be null!"); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveServerCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveServerCommands.java index 2a04c1fda..4ea0b28f3 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveServerCommands.java @@ -133,7 +133,7 @@ class LettuceReactiveServerCommands implements ReactiveServerCommands { @Override public Mono info(String section) { - Assert.hasText(section, "Section must not be null nor empty!"); + Assert.hasText(section, "Section must not be null or empty!"); return connection.execute(c -> c.info(section)) // .map(LettuceConverters::toProperties) // @@ -147,7 +147,7 @@ class LettuceReactiveServerCommands implements ReactiveServerCommands { @Override public Mono getConfig(String pattern) { - Assert.hasText(pattern, "Pattern must not be null nor empty!"); + Assert.hasText(pattern, "Pattern must not be null or empty!"); return connection.execute(c -> c.configGet(pattern)) // .map(LettuceConverters::toProperties).next(); @@ -160,8 +160,8 @@ class LettuceReactiveServerCommands implements ReactiveServerCommands { @Override public Mono setConfig(String param, String value) { - Assert.hasText(param, "Param must not be null nor empty!"); - Assert.hasText(value, "Value must not be null nor empty!"); + Assert.hasText(param, "Parameter must not be null or empty!"); + Assert.hasText(value, "Value must not be null or empty!"); return connection.execute(c -> c.configSet(param, value)).next(); } @@ -195,7 +195,7 @@ class LettuceReactiveServerCommands implements ReactiveServerCommands { @Override public Mono killClient(String host, int port) { - Assert.notNull(host, "Host must not be null nor empty!"); + Assert.notNull(host, "Host must not be null or empty!"); return connection.execute(c -> c.clientKill(String.format("%s:%s", host, port))).next(); } @@ -207,7 +207,7 @@ class LettuceReactiveServerCommands implements ReactiveServerCommands { @Override public Mono setClientName(String name) { - Assert.hasText(name, "Name must not be null nor empty!"); + Assert.hasText(name, "Name must not be null or empty!"); return connection.execute(c -> c.clientSetname(ByteBuffer.wrap(LettuceConverters.toBytes(name)))).next(); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java index fce79a715..4b7418607 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceScriptingCommands.java @@ -27,6 +27,7 @@ import org.springframework.data.redis.connection.RedisScriptingCommands; import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; +import org.springframework.util.Assert; /** * @author Mark Paluch @@ -46,6 +47,7 @@ class LettuceScriptingCommands implements RedisScriptingCommands { */ @Override public void scriptFlush() { + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().scriptFlush())); @@ -67,18 +69,16 @@ class LettuceScriptingCommands implements RedisScriptingCommands { */ @Override public void scriptKill() { + if (isQueueing()) { throw new UnsupportedOperationException("Script kill not permitted in a transaction"); } + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().scriptKill())); return; } - if (isQueueing()) { - transaction(connection.newLettuceTxStatusResult(getConnection().scriptKill())); - return; - } getConnection().scriptKill(); } catch (Exception ex) { throw convertLettuceAccessException(ex); @@ -91,6 +91,9 @@ class LettuceScriptingCommands implements RedisScriptingCommands { */ @Override public String scriptLoad(byte[] script) { + + Assert.notNull(script, "Script must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().scriptLoad(script))); @@ -112,6 +115,10 @@ class LettuceScriptingCommands implements RedisScriptingCommands { */ @Override public List scriptExists(String... scriptSha1) { + + Assert.notNull(scriptSha1, "Script digests must not be null!"); + Assert.noNullElements(scriptSha1, "Script digests must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().scriptExists(scriptSha1))); @@ -133,6 +140,9 @@ class LettuceScriptingCommands implements RedisScriptingCommands { */ @Override public T eval(byte[] script, ReturnType returnType, int numKeys, byte[]... keysAndArgs) { + + Assert.notNull(script, "Script must not be null!"); + try { byte[][] keys = extractScriptKeys(numKeys, keysAndArgs); byte[][] args = extractScriptArgs(numKeys, keysAndArgs); @@ -162,6 +172,9 @@ class LettuceScriptingCommands implements RedisScriptingCommands { */ @Override public T evalSha(String scriptSha1, ReturnType returnType, int numKeys, byte[]... keysAndArgs) { + + Assert.notNull(scriptSha1, "Script digest must not be null!"); + try { byte[][] keys = extractScriptKeys(numKeys, keysAndArgs); byte[][] args = extractScriptArgs(numKeys, keysAndArgs); @@ -191,6 +204,9 @@ class LettuceScriptingCommands implements RedisScriptingCommands { */ @Override public T evalSha(byte[] scriptSha1, ReturnType returnType, int numKeys, byte[]... keysAndArgs) { + + Assert.notNull(scriptSha1, "Script digest must not be null!"); + return evalSha(LettuceConverters.toString(scriptSha1), returnType, numKeys, keysAndArgs); } 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 97f68d210..db54cfd16 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 @@ -17,6 +17,8 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.List; import java.util.Properties; @@ -35,13 +37,10 @@ import org.springframework.util.Assert; * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class LettuceServerCommands implements RedisServerCommands { - private final LettuceConnection connection; - - LettuceServerCommands(LettuceConnection connection) { - this.connection = connection; - } + private final @NonNull LettuceConnection connection; /* * (non-Javadoc) @@ -49,6 +48,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void bgReWriteAof() { + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().bgrewriteaof())); @@ -70,6 +70,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void bgSave() { + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().bgsave())); @@ -91,6 +92,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public Long lastSave() { + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().lastsave(), LettuceConverters.dateToLong())); @@ -112,6 +114,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void save() { + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().save())); @@ -133,6 +136,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public Long dbSize() { + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().dbsize())); @@ -154,6 +158,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void flushDb() { + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().flushdb())); @@ -175,6 +180,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void flushAll() { + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().flushall())); @@ -196,6 +202,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public Properties info() { + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().info(), LettuceConverters.stringToProps())); @@ -217,6 +224,9 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public Properties info(String section) { + + Assert.hasText(section, "Section must not be null or empty!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().info(section), LettuceConverters.stringToProps())); @@ -238,6 +248,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void shutdown() { + try { if (isPipelined()) { getAsyncConnection().shutdown(true); @@ -278,19 +289,22 @@ class LettuceServerCommands implements RedisServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#getConfig(java.lang.String) */ @Override - public Properties getConfig(String param) { + public Properties getConfig(String pattern) { + + Assert.hasText(pattern, "Pattern must not be null or empty!"); + try { if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().configGet(param), Converters.mapToPropertiesConverter())); + pipeline(connection.newLettuceResult(getAsyncConnection().configGet(pattern), + Converters.mapToPropertiesConverter())); return null; } if (isQueueing()) { transaction( - connection.newLettuceTxResult(getConnection().configGet(param), Converters.mapToPropertiesConverter())); + connection.newLettuceTxResult(getConnection().configGet(pattern), Converters.mapToPropertiesConverter())); return null; } - return Converters.toProperties(getConnection().configGet(param)); + return Converters.toProperties(getConnection().configGet(pattern)); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -302,6 +316,10 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void setConfig(String param, String value) { + + Assert.hasText(param, "Parameter must not be null or empty!"); + Assert.hasText(value, "Value must not be null or empty!"); + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().configSet(param, value))); @@ -323,6 +341,7 @@ class LettuceServerCommands implements RedisServerCommands { */ @Override public void resetConfigStats() { + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().configResetstat())); @@ -346,7 +365,6 @@ class LettuceServerCommands implements RedisServerCommands { public Long time() { try { - if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().time(), LettuceConverters.toTimeConverter())); return null; @@ -355,7 +373,6 @@ class LettuceServerCommands implements RedisServerCommands { transaction(connection.newLettuceTxResult(getConnection().time(), LettuceConverters.toTimeConverter())); return null; } - return LettuceConverters.toTimeConverter().convert(getConnection().time()); } catch (Exception ex) { throw convertLettuceAccessException(ex); @@ -390,6 +407,8 @@ class LettuceServerCommands implements RedisServerCommands { @Override public void setClientName(byte[] name) { + Assert.notNull(name, "Name must not be null!"); + if (isQueueing()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().clientSetname(name))); return; @@ -410,7 +429,6 @@ class LettuceServerCommands implements RedisServerCommands { public String getClientName() { try { - if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().clientGetname(), LettuceConverters.bytesToString())); return null; @@ -419,7 +437,6 @@ class LettuceServerCommands implements RedisServerCommands { transaction(connection.newLettuceTxResult(getConnection().clientGetname(), LettuceConverters.bytesToString())); return null; } - return LettuceConverters.toString(getConnection().clientGetname()); } catch (Exception ex) { throw convertLettuceAccessException(ex); @@ -453,6 +470,7 @@ class LettuceServerCommands implements RedisServerCommands { public void slaveOf(String host, int port) { Assert.hasText(host, "Host must not be null for 'SLAVEOF' command."); + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().slaveof(host, port))); @@ -506,6 +524,9 @@ class LettuceServerCommands implements RedisServerCommands { @Override public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, long timeout) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(target, "Target node must not be null!"); + try { if (isPipelined()) { pipeline(connection diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java index 8e6df4c1c..7b28feed5 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSetCommands.java @@ -19,6 +19,8 @@ import io.lettuce.core.ScanArgs; import io.lettuce.core.ValueScanCursor; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.ArrayList; import java.util.List; @@ -33,19 +35,17 @@ import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.KeyBoundCursor; import org.springframework.data.redis.core.ScanIteration; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.util.Assert; /** * @author Christoph Strobl * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class LettuceSetCommands implements RedisSetCommands { - private final LettuceConnection connection; - - LettuceSetCommands(LettuceConnection connection) { - this.connection = connection; - } + private final @NonNull LettuceConnection connection; /* * (non-Javadoc) @@ -53,6 +53,11 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Long sAdd(byte[] key, byte[]... values) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().sadd(key, values))); @@ -74,6 +79,9 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Long sCard(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().scard(key))); @@ -95,6 +103,10 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Set sDiff(byte[]... keys) { + + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().sdiff(keys))); @@ -116,6 +128,11 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Long sDiffStore(byte[] destKey, byte[]... keys) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().sdiffstore(destKey, keys))); @@ -137,6 +154,10 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Set sInter(byte[]... keys) { + + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().sinter(keys))); @@ -158,6 +179,11 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Long sInterStore(byte[] destKey, byte[]... keys) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().sinterstore(destKey, keys))); @@ -179,6 +205,10 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Boolean sIsMember(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().sismember(key, value))); @@ -200,6 +230,9 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Set sMembers(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().smembers(key))); @@ -221,6 +254,11 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { + + Assert.notNull(srcKey, "Source key must not be null!"); + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().smove(srcKey, destKey, value))); @@ -242,6 +280,9 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public byte[] sPop(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().spop(key))); @@ -263,10 +304,12 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public List sPop(byte[] key, long count) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().spop(key, count), - ArrayList::new)); + pipeline(connection.newLettuceResult(getAsyncConnection().spop(key, count), ArrayList::new)); return null; } if (isQueueing()) { @@ -286,6 +329,9 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public byte[] sRandMember(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().srandmember(key))); @@ -307,6 +353,9 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public List sRandMember(byte[] key, long count) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().srandmember(key, count))); @@ -329,6 +378,11 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Long sRem(byte[] key, byte[]... values) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().srem(key, values))); @@ -350,6 +404,10 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Set sUnion(byte[]... keys) { + + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().sunion(keys))); @@ -371,6 +429,11 @@ class LettuceSetCommands implements RedisSetCommands { */ @Override public Long sUnionStore(byte[] destKey, byte[]... keys) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(keys, "Source keys must not be null!"); + Assert.noNullElements(keys, "Source keys must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().sunionstore(destKey, keys))); @@ -404,6 +467,8 @@ class LettuceSetCommands implements RedisSetCommands { */ public Cursor sScan(byte[] key, long cursorId, ScanOptions options) { + Assert.notNull(key, "Key must not be null!"); + return new KeyBoundCursor(key, cursorId, options) { @Override diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java index 4966281fb..af3dfc38b 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceStringCommands.java @@ -17,6 +17,8 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.List; import java.util.Map; @@ -34,15 +36,20 @@ import org.springframework.util.Assert; * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class LettuceStringCommands implements RedisStringCommands { - private final LettuceConnection connection; - - LettuceStringCommands(LettuceConnection connection) { - this.connection = connection; - } + private final @NonNull LettuceConnection connection; + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#get(byte[]) + */ + @Override public byte[] get(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().get(key))); @@ -58,7 +65,69 @@ class LettuceStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#getSet(byte[], byte[]) + */ + @Override + public byte[] getSet(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().getset(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().getset(key, value))); + return null; + } + return getConnection().getset(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#mGet(byte[][]) + */ + @Override + public List mGet(byte[]... keys) { + + Assert.notNull(keys, "Keys must not be null!"); + Assert.noNullElements(keys, "Keys must not contain null elements!"); + + try { + if (isPipelined()) { + pipeline( + connection.newLettuceResult(getAsyncConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); + return null; + } + if (isQueueing()) { + transaction( + connection.newLettuceTxResult(getConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); + return null; + } + + return LettuceConverters. keyValueListUnwrapper().convert(getConnection().mget(keys)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#set(byte[], byte[]) + */ + @Override public void set(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().set(key, value))); @@ -81,6 +150,8 @@ class LettuceStringCommands implements RedisStringCommands { @Override public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); Assert.notNull(expiration, "Expiration must not be null!"); Assert.notNull(option, "Option must not be null!"); @@ -101,112 +172,66 @@ class LettuceStringCommands implements RedisStringCommands { } } - public byte[] getSet(byte[] key, byte[] value) { + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setNX(byte[], byte[]) + */ + @Override + public Boolean setNX(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().getset(key, value))); + pipeline(connection.newLettuceResult(getAsyncConnection().setnx(key, value))); return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().getset(key, value))); + transaction(connection.newLettuceTxResult(getConnection().setnx(key, value))); return null; } - return getConnection().getset(key, value); + return getConnection().setnx(key, value); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } - public Long append(byte[] key, byte[] value) { + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setEx(byte[], long, byte[]) + */ + @Override + public void setEx(byte[] key, long seconds, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().append(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().append(key, value))); - return null; - } - return getConnection().append(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public List mGet(byte[]... keys) { - try { - if (isPipelined()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); - return null; - } - if (isQueueing()) { - transaction( - connection.newLettuceTxResult(getConnection().mget(keys), LettuceConverters.keyValueListUnwrapper())); - return null; - } - - return LettuceConverters. keyValueListUnwrapper().convert(getConnection().mget(keys)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void mSet(Map tuples) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().mset(tuples))); + pipeline(connection.newLettuceStatusResult(getAsyncConnection().setex(key, seconds, value))); return; } if (isQueueing()) { - transaction(connection.newLettuceTxStatusResult(getConnection().mset(tuples))); + transaction(connection.newLettuceTxStatusResult(getConnection().setex(key, seconds, value))); return; } - getConnection().mset(tuples); + getConnection().setex(key, seconds, value); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } - public Boolean mSetNX(Map tuples) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().msetnx(tuples))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().msetnx(tuples))); - return null; - } - return getConnection().msetnx(tuples); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public void setEx(byte[] key, long time, byte[] value) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().setex(key, time, value))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceTxStatusResult(getConnection().setex(key, time, value))); - return; - } - getConnection().setex(key, time, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /** - * @since 1.3 + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisStringCommands#pSetEx(byte[], long, byte[]) */ @Override public void pSetEx(byte[] key, long milliseconds, byte[] value) { + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult(getAsyncConnection().psetex(key, milliseconds, value))); @@ -222,71 +247,63 @@ class LettuceStringCommands implements RedisStringCommands { } } - public Boolean setNX(byte[] key, byte[] value) { + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#mSet(java.util.Map) + */ + @Override + public void mSet(Map tuples) { + + Assert.notNull(tuples, "Tuples must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().setnx(key, value))); - return null; + pipeline(connection.newLettuceStatusResult(getAsyncConnection().mset(tuples))); + return; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().setnx(key, value))); - return null; + transaction(connection.newLettuceTxStatusResult(getConnection().mset(tuples))); + return; } - return getConnection().setnx(key, value); + getConnection().mset(tuples); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } - public byte[] getRange(byte[] key, long start, long end) { + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#mSetNX(java.util.Map) + */ + @Override + public Boolean mSetNX(Map tuples) { + + Assert.notNull(tuples, "Tuples must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().getrange(key, start, end))); + pipeline(connection.newLettuceResult(getAsyncConnection().msetnx(tuples))); return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().getrange(key, start, end))); + transaction(connection.newLettuceTxResult(getConnection().msetnx(tuples))); return null; } - return getConnection().getrange(key, start, end); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long decr(byte[] key) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().decr(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().decr(key))); - return null; - } - return getConnection().decr(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long decrBy(byte[] key, long value) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().decrby(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().decrby(key, value))); - return null; - } - return getConnection().decrby(key, value); + return getConnection().msetnx(tuples); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#incr(byte[]) + */ + @Override public Long incr(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().incr(key))); @@ -302,7 +319,15 @@ class LettuceStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#incrBy(byte[], long) + */ + @Override public Long incrBy(byte[] key, long value) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().incrby(key, value))); @@ -318,7 +343,15 @@ class LettuceStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#incrBy(byte[], double) + */ + @Override public Double incrBy(byte[] key, double value) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().incrbyfloat(key, value))); @@ -334,7 +367,137 @@ class LettuceStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#decr(byte[]) + */ + @Override + public Long decr(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().decr(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().decr(key))); + return null; + } + return getConnection().decr(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#decrBy(byte[], long) + */ + @Override + public Long decrBy(byte[] key, long value) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().decrby(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().decrby(key, value))); + return null; + } + return getConnection().decrby(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#append(byte[], byte[]) + */ + @Override + public Long append(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().append(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().append(key, value))); + return null; + } + return getConnection().append(key, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#getRange(byte[], long, long) + */ + @Override + public byte[] getRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().getrange(key, start, end))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().getrange(key, start, end))); + return null; + } + return getConnection().getrange(key, start, end); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setRange(byte[], byte[], long) + */ + @Override + public void setRange(byte[] key, byte[] value, long offset) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceStatusResult(getAsyncConnection().setrange(key, offset, value))); + return; + } + if (isQueueing()) { + transaction(connection.newLettuceTxStatusResult(getConnection().setrange(key, offset, value))); + return; + } + getConnection().setrange(key, offset, value); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#getBit(byte[], long) + */ + @Override public Boolean getBit(byte[] key, long offset) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline( @@ -352,7 +515,15 @@ class LettuceStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#setBit(byte[], long, boolean) + */ + @Override public Boolean setBit(byte[] key, long offset, boolean value) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().setbit(key, offset, LettuceConverters.toInt(value)), @@ -371,39 +542,15 @@ class LettuceStringCommands implements RedisStringCommands { } } - public void setRange(byte[] key, byte[] value, long start) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceStatusResult(getAsyncConnection().setrange(key, start, value))); - return; - } - if (isQueueing()) { - transaction(connection.newLettuceTxStatusResult(getConnection().setrange(key, start, value))); - return; - } - getConnection().setrange(key, start, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - public Long strLen(byte[] key) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().strlen(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().strlen(key))); - return null; - } - return getConnection().strlen(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#bitCount(byte[]) + */ + @Override public Long bitCount(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().bitcount(key))); @@ -419,23 +566,43 @@ class LettuceStringCommands implements RedisStringCommands { } } - public Long bitCount(byte[] key, long begin, long end) { + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#bitCount(byte[], long, long) + */ + @Override + public Long bitCount(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().bitcount(key, begin, end))); + pipeline(connection.newLettuceResult(getAsyncConnection().bitcount(key, start, end))); return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().bitcount(key, begin, end))); + transaction(connection.newLettuceTxResult(getConnection().bitcount(key, start, end))); return null; } - return getConnection().bitcount(key, begin, end); + return getConnection().bitcount(key, start, end); } catch (Exception ex) { throw convertLettuceAccessException(ex); } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#bitOp(org.springframework.data.redis.connection.RedisStringCommands.BitOperation, byte[], byte[][]) + */ + @Override public Long bitOp(BitOperation op, byte[] destination, byte[]... keys) { + + Assert.notNull(op, "BitOperation must not be null!"); + Assert.notNull(destination, "Destination key must not be null!"); + + if (op == BitOperation.NOT && keys.length > 1) { + throw new UnsupportedOperationException("Bitop NOT should only be performed against one key"); + } try { if (isPipelined()) { pipeline(connection.newLettuceResult(asyncBitOp(op, destination, keys))); @@ -489,6 +656,30 @@ class LettuceStringCommands implements RedisStringCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisStringCommands#strLen(byte[]) + */ + @Override + public Long strLen(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().strlen(key))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().strlen(key))); + return null; + } + return getConnection().strlen(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + private boolean isPipelined() { return connection.isPipelined(); } 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 d2cb7e3f7..2380a9fed 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 @@ -21,6 +21,8 @@ import io.lettuce.core.ScoredValueScanCursor; import io.lettuce.core.ZStoreArgs; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import java.util.List; import java.util.Set; @@ -40,13 +42,10 @@ import org.springframework.util.Assert; * @author Mark Paluch * @since 2.0 */ +@RequiredArgsConstructor class LettuceZSetCommands implements RedisZSetCommands { - private final LettuceConnection connection; - - LettuceZSetCommands(LettuceConnection connection) { - this.connection = connection; - } + private final @NonNull LettuceConnection connection; /* * (non-Javadoc) @@ -54,6 +53,10 @@ class LettuceZSetCommands implements RedisZSetCommands { */ @Override public Boolean zAdd(byte[] key, double score, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().zadd(key, score, value), @@ -77,6 +80,10 @@ class LettuceZSetCommands implements RedisZSetCommands { */ @Override public Long zAdd(byte[] key, Set tuples) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(tuples, "Tuples must not be null!"); + try { if (isPipelined()) { pipeline( @@ -96,44 +103,25 @@ class LettuceZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRem(byte[], byte[][]) */ @Override - public Long zCard(byte[] key) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zcard(key))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().zcard(key))); - return null; - } - return getConnection().zcard(key); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } + public Long zRem(byte[] key, byte[]... values) { - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) - */ - @Override - public Long zCount(byte[] key, Range range) { - - Assert.notNull(range, "Range for ZCOUNT must not be null!"); + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(values, "Values must not be null!"); + Assert.noNullElements(values, "Values must not contain null elements!"); try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zcount(key, LettuceConverters.toRange(range)))); + pipeline(connection.newLettuceResult(getAsyncConnection().zrem(key, values))); return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().zcount(key, LettuceConverters.toRange(range)))); + transaction(connection.newLettuceTxResult(getConnection().zrem(key, values))); return null; } - return getConnection().zcount(key, LettuceConverters.toRange(range)); + return getConnection().zrem(key, values); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -145,6 +133,10 @@ class LettuceZSetCommands implements RedisZSetCommands { */ @Override public Double zIncrBy(byte[] key, double increment, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().zincrby(key, increment, value))); @@ -162,23 +154,24 @@ class LettuceZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[]) */ @Override - public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + public Long zRank(byte[] key, byte[] value) { - ZStoreArgs storeArgs = zStoreArgs(aggregate, weights); + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, storeArgs, sets))); + pipeline(connection.newLettuceResult(getAsyncConnection().zrank(key, value))); return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().zinterstore(destKey, storeArgs, sets))); + transaction(connection.newLettuceTxResult(getConnection().zrank(key, value))); return null; } - return getConnection().zinterstore(destKey, storeArgs, sets); + return getConnection().zrank(key, value); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -186,20 +179,23 @@ class LettuceZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], byte[][]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRank(byte[], byte[]) */ @Override - public Long zInterStore(byte[] destKey, byte[]... sets) { + public Long zRevRank(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, sets))); + pipeline(connection.newLettuceResult(getAsyncConnection().zrevrank(key, value))); return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().zinterstore(destKey, sets))); + transaction(connection.newLettuceTxResult(getConnection().zrevrank(key, value))); return null; } - return getConnection().zinterstore(destKey, sets); + return getConnection().zrevrank(key, value); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -211,6 +207,9 @@ class LettuceZSetCommands implements RedisZSetCommands { */ @Override public Set zRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().zrange(key, start, end), @@ -234,6 +233,9 @@ class LettuceZSetCommands implements RedisZSetCommands { */ @Override public Set zRangeWithScores(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().zrangeWithScores(key, start, end), @@ -251,50 +253,6 @@ class LettuceZSetCommands implements RedisZSetCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) - */ - @Override - public Set zRangeByScore(byte[] key, Range range, Limit limit) { - - Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); - Assert.notNull(limit, "Limit must not be null!"); - - try { - if (isPipelined()) { - if (limit.isUnlimited()) { - pipeline( - connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } else { - pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (isQueueing()) { - if (limit.isUnlimited()) { - transaction( - connection.newLettuceTxResult(getConnection().zrangebyscore(key, LettuceConverters.toRange(range)), - LettuceConverters.bytesListToBytesSet())); - } else { - transaction(connection.newLettuceTxResult( - getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.bytesListToBytesSet())); - } - return null; - } - if (limit.isUnlimited()) { - return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, LettuceConverters.toRange(range))); - } - return LettuceConverters.toBytesSet( - getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScoreWithScores(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) @@ -302,6 +260,7 @@ class LettuceZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); Assert.notNull(limit, "Limit must not be null!"); @@ -341,12 +300,41 @@ class LettuceZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRange(byte[], long, long) + */ + @Override + public Set zRevRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrevrange(key, start, end), + LettuceConverters.bytesListToBytesSet())); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zrevrange(key, start, end), + LettuceConverters.bytesListToBytesSet())); + return null; + } + return LettuceConverters.toBytesSet(getConnection().zrevrange(key, start, end)); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRangeWithScores(byte[], long, long) */ @Override public Set zRevRangeWithScores(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().zrevrangeWithScores(key, start, end), @@ -371,6 +359,7 @@ class LettuceZSetCommands implements RedisZSetCommands { @Override public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREVRANGEBYSCORE must not be null!"); Assert.notNull(limit, "Limit must not be null!"); @@ -416,6 +405,7 @@ class LettuceZSetCommands implements RedisZSetCommands { @Override public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREVRANGEBYSCOREWITHSCORES must not be null!"); Assert.notNull(limit, "Limit must not be null!"); @@ -432,6 +422,7 @@ class LettuceZSetCommands implements RedisZSetCommands { } return null; } + if (isQueueing()) { if (limit.isUnlimited()) { transaction(connection.newLettuceTxResult( @@ -457,20 +448,23 @@ class LettuceZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRank(byte[], byte[]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCount(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range) */ @Override - public Long zRank(byte[] key, byte[] value) { + public Long zCount(byte[] key, Range range) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrank(key, value))); + pipeline(connection.newLettuceResult(getAsyncConnection().zcount(key, LettuceConverters.toRange(range)))); return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().zrank(key, value))); + transaction(connection.newLettuceTxResult(getConnection().zcount(key, LettuceConverters.toRange(range)))); return null; } - return getConnection().zrank(key, value); + return getConnection().zcount(key, LettuceConverters.toRange(range)); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -478,20 +472,48 @@ class LettuceZSetCommands implements RedisZSetCommands { /* * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRem(byte[], byte[][]) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zCard(byte[]) */ @Override - public Long zRem(byte[] key, byte[]... values) { + public Long zCard(byte[] key) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrem(key, values))); + pipeline(connection.newLettuceResult(getAsyncConnection().zcard(key))); return null; } if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().zrem(key, values))); + transaction(connection.newLettuceTxResult(getConnection().zcard(key))); return null; } - return getConnection().zrem(key, values); + return getConnection().zcard(key); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zScore(byte[], byte[]) + */ + @Override + public Double zScore(byte[] key, byte[] value) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(value, "Value must not be null!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zscore(key, value))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zscore(key, value))); + return null; + } + return getConnection().zscore(key, value); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -503,6 +525,9 @@ class LettuceZSetCommands implements RedisZSetCommands { */ @Override public Long zRemRange(byte[] key, long start, long end) { + + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().zremrangebyrank(key, start, end))); @@ -525,6 +550,7 @@ class LettuceZSetCommands implements RedisZSetCommands { @Override public Long zRemRangeByScore(byte[] key, Range range) { + Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range for ZREMRANGEBYSCORE must not be null!"); try { @@ -544,77 +570,17 @@ class LettuceZSetCommands implements RedisZSetCommands { } } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRange(byte[], long, long) - */ - @Override - public Set zRevRange(byte[] key, long start, long end) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrevrange(key, start, end), - LettuceConverters.bytesListToBytesSet())); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().zrevrange(key, start, end), - LettuceConverters.bytesListToBytesSet())); - return null; - } - return LettuceConverters.toBytesSet(getConnection().zrevrange(key, start, end)); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zRevRank(byte[], byte[]) - */ - @Override - public Long zRevRank(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrevrank(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().zrevrank(key, value))); - return null; - } - return getConnection().zrevrank(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.connection.RedisZSetCommands#zScore(byte[], byte[]) - */ - @Override - public Double zScore(byte[] key, byte[] value) { - try { - if (isPipelined()) { - pipeline(connection.newLettuceResult(getAsyncConnection().zscore(key, value))); - return null; - } - if (isQueueing()) { - transaction(connection.newLettuceTxResult(getConnection().zscore(key, value))); - return null; - } - return getConnection().zscore(key, value); - } catch (Exception ex) { - throw convertLettuceAccessException(ex); - } - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zUnionStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) */ @Override public Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + ZStoreArgs storeArgs = zStoreArgs(aggregate, weights); try { @@ -638,6 +604,11 @@ class LettuceZSetCommands implements RedisZSetCommands { */ @Override public Long zUnionStore(byte[] destKey, byte[]... sets) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().zunionstore(destKey, sets))); @@ -653,6 +624,60 @@ class LettuceZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, int[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + + ZStoreArgs storeArgs = zStoreArgs(aggregate, weights); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, storeArgs, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zinterstore(destKey, storeArgs, sets))); + return null; + } + return getConnection().zinterstore(destKey, storeArgs, sets); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zInterStore(byte[], byte[][]) + */ + @Override + public Long zInterStore(byte[] destKey, byte[]... sets) { + + Assert.notNull(destKey, "Destination key must not be null!"); + Assert.notNull(sets, "Source sets must not be null!"); + Assert.noNullElements(sets, "Source sets must not contain null elements!"); + + try { + if (isPipelined()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zinterstore(destKey, sets))); + return null; + } + if (isQueueing()) { + transaction(connection.newLettuceTxResult(getConnection().zinterstore(destKey, sets))); + return null; + } + return getConnection().zinterstore(destKey, sets); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zScan(byte[], org.springframework.data.redis.core.ScanOptions) @@ -671,6 +696,8 @@ class LettuceZSetCommands implements RedisZSetCommands { */ public Cursor zScan(byte[] key, long cursorId, ScanOptions options) { + Assert.notNull(key, "Key must not be null!"); + return new KeyBoundCursor(key, cursorId, options) { @Override @@ -692,6 +719,7 @@ class LettuceZSetCommands implements RedisZSetCommands { return new ScanIteration<>(Long.valueOf(nextCursorId), values); } + @Override protected void doClose() { LettuceZSetCommands.this.connection.close(); } @@ -706,6 +734,8 @@ class LettuceZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScore(byte[] key, String min, String max) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, min, max), @@ -730,6 +760,8 @@ class LettuceZSetCommands implements RedisZSetCommands { @Override public Set zRangeByScore(byte[] key, String min, String max, long offset, long count) { + Assert.notNull(key, "Key must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, min, max, offset, count), @@ -747,6 +779,51 @@ class LettuceZSetCommands implements RedisZSetCommands { } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByScore(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) + */ + @Override + public Set zRangeByScore(byte[] key, Range range, Limit limit) { + + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range for ZRANGEBYSCORE must not be null!"); + Assert.notNull(limit, "Limit must not be null!"); + + try { + if (isPipelined()) { + if (limit.isUnlimited()) { + pipeline( + connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range)), + LettuceConverters.bytesListToBytesSet())); + } else { + pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range), + LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); + } + return null; + } + if (isQueueing()) { + if (limit.isUnlimited()) { + transaction( + connection.newLettuceTxResult(getConnection().zrangebyscore(key, LettuceConverters.toRange(range)), + LettuceConverters.bytesListToBytesSet())); + } else { + transaction(connection.newLettuceTxResult( + getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.bytesListToBytesSet())); + } + return null; + } + if (limit.isUnlimited()) { + return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, LettuceConverters.toRange(range))); + } + return LettuceConverters.toBytesSet( + getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + } catch (Exception ex) { + throw convertLettuceAccessException(ex); + } + } + /* * (non-Javadoc) * @see org.springframework.data.redis.connection.RedisZSetCommands#zRangeByLex(byte[], org.springframework.data.redis.connection.RedisZSetCommands.Range, org.springframework.data.redis.connection.RedisZSetCommands.Limit) @@ -754,7 +831,8 @@ class LettuceZSetCommands implements RedisZSetCommands { @Override public Set zRangeByLex(byte[] key, Range range, Limit limit) { - Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); + Assert.notNull(key, "Key must not be null!"); + Assert.notNull(range, "Range for ZRANGEBYLEX must not be null!"); Assert.notNull(limit, "Limit must not be null!"); try { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/StandaloneConnectionProvider.java b/src/main/java/org/springframework/data/redis/connection/lettuce/StandaloneConnectionProvider.java index 1c5fc0151..07e974f7e 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/StandaloneConnectionProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/StandaloneConnectionProvider.java @@ -21,6 +21,7 @@ import io.lettuce.core.api.StatefulConnection; import io.lettuce.core.codec.RedisCodec; import io.lettuce.core.pubsub.StatefulRedisPubSubConnection; import io.lettuce.core.sentinel.api.StatefulRedisSentinelConnection; +import lombok.RequiredArgsConstructor; import org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider.TargetAware; @@ -29,23 +30,20 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionProvid * @author Christoph Strobl * @since 2.0 */ +@RequiredArgsConstructor class StandaloneConnectionProvider implements LettuceConnectionProvider, TargetAware { private final RedisClient client; private final RedisCodec codec; - StandaloneConnectionProvider(RedisClient client, RedisCodec codec) { - - this.client = client; - this.codec = codec; - } - /* * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider#getConnection(java.lang.Class) */ + @SuppressWarnings("null") @Override public > T getConnection(Class connectionType) { + if (connectionType.equals(StatefulRedisSentinelConnection.class)) { return connectionType.cast(client.connectSentinel()); } @@ -65,6 +63,7 @@ class StandaloneConnectionProvider implements LettuceConnectionProvider, TargetA * (non-Javadoc) * @see org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider.TargetAware#getConnection(java.lang.Class, io.lettuce.core.RedisURI) */ + @SuppressWarnings("null") @Override public > T getConnection(Class connectionType, RedisURI redisURI) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/package-info.java b/src/main/java/org/springframework/data/redis/connection/lettuce/package-info.java index f8b09f070..6a8dd8d25 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/package-info.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/package-info.java @@ -2,4 +2,5 @@ * Connection package for Lettuce Redis client. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.connection.lettuce; diff --git a/src/main/java/org/springframework/data/redis/connection/package-info.java b/src/main/java/org/springframework/data/redis/connection/package-info.java index 4c78de6fc..e8ea570a9 100644 --- a/src/main/java/org/springframework/data/redis/connection/package-info.java +++ b/src/main/java/org/springframework/data/redis/connection/package-info.java @@ -1,9 +1,9 @@ /** - * Connection package providing low-level abstractions for interacting with - * the various Redis 'drivers'/libraries. - * - *

Performs exception translation between the underlying library exceptions to Spring's DAO hierarchy. + * Connection package providing low-level abstractions for interacting with the various Redis 'drivers'/libraries. + *

+ * Performs exception translation between the underlying library exceptions to Spring's DAO hierarchy. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.connection; diff --git a/src/main/java/org/springframework/data/redis/connection/util/package-info.java b/src/main/java/org/springframework/data/redis/connection/util/package-info.java index 05f261de6..b655016f0 100644 --- a/src/main/java/org/springframework/data/redis/connection/util/package-info.java +++ b/src/main/java/org/springframework/data/redis/connection/util/package-info.java @@ -2,5 +2,6 @@ * Internal utility package for encoding/decoding Strings to byte[] (using Base64) library. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.connection.util; 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 442f83762..fd5717a8e 100644 --- a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java +++ b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java @@ -60,6 +60,7 @@ abstract class AbstractOperations { return deserializeValue(result); } + @Nullable protected abstract byte[] inRedis(byte[] rawKey, RedisConnection connection); } @@ -286,7 +287,7 @@ abstract class AbstractOperations { @SuppressWarnings("unchecked") Map deserializeHashMap(@Nullable Map entries) { // connection in pipeline/multi mode - + if (entries == null) { return null; } diff --git a/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java b/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java index 031472071..be7d3fc88 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2017 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 - * + * * http://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. @@ -21,7 +21,7 @@ import org.springframework.lang.Nullable; /** * Value (or String in Redis terminology) operations bound to a certain key. - * + * * @author Costin Leau * @author Mark Paluch */ @@ -58,7 +58,7 @@ public interface BoundValueOperations extends BoundKeyOperations { /** * Get the value of the bound key. * - * @return {@literal null} when used in pipeline / transaction.ø + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GET */ @Nullable @@ -67,7 +67,7 @@ public interface BoundValueOperations extends BoundKeyOperations { /** * Set {@code value} of the bound key and return its old value. * - * @return {@literal null} when used in pipeline / transaction.ø + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GETSET */ @Nullable @@ -108,6 +108,7 @@ public interface BoundValueOperations extends BoundKeyOperations { * * @param start * @param end + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GETRANGE */ @Nullable diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveGeoOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveGeoOperations.java index 6757c7300..397e45886 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveGeoOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveGeoOperations.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -44,26 +46,11 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @since 2.0 */ +@RequiredArgsConstructor class DefaultReactiveGeoOperations implements ReactiveGeoOperations { - private final ReactiveRedisTemplate template; - private final RedisSerializationContext serializationContext; - - /** - * Create new instance of {@link DefaultReactiveGeoOperations}. - * - * @param template must not be {@literal null}. - * @param serializationContext must not be {@literal null}. - */ - DefaultReactiveGeoOperations(ReactiveRedisTemplate template, - RedisSerializationContext serializationContext) { - - Assert.notNull(template, "ReactiveRedisTemplate must not be null!"); - Assert.notNull(serializationContext, "RedisSerializationContext must not be null!"); - - this.template = template; - this.serializationContext = serializationContext; - } + private final @NonNull ReactiveRedisTemplate template; + private final @NonNull RedisSerializationContext serializationContext; /* * (non-Javadoc) diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java index 2cc9e4414..bc0e06c15 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -38,26 +40,11 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @since 2.0 */ +@RequiredArgsConstructor class DefaultReactiveHashOperations implements ReactiveHashOperations { - private final ReactiveRedisTemplate template; - private final RedisSerializationContext serializationContext; - - /** - * Creates new instance of {@link DefaultReactiveHashOperations}. - * - * @param template must not be {@literal null}. - * @param serializationContext must not be {@literal null}. - */ - DefaultReactiveHashOperations(ReactiveRedisTemplate template, - RedisSerializationContext serializationContext) { - - Assert.notNull(template, "ReactiveRedisTemplate must not be null!"); - Assert.notNull(serializationContext, "RedisSerializationContext must not be null!"); - - this.template = template; - this.serializationContext = serializationContext; - } + private final @NonNull ReactiveRedisTemplate template; + private final @NonNull RedisSerializationContext serializationContext; /* (non-Javadoc) * @see org.springframework.data.redis.core.ReactiveHashOperations#delete(java.lang.Object, java.lang.Object[]) diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveHyperLogLogOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveHyperLogLogOperations.java index e4ba3d417..3b6c127f0 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveHyperLogLogOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveHyperLogLogOperations.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -33,26 +35,11 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @since 2.0 */ +@RequiredArgsConstructor class DefaultReactiveHyperLogLogOperations implements ReactiveHyperLogLogOperations { - private final ReactiveRedisTemplate template; - private final RedisSerializationContext serializationContext; - - /** - * Creates new instance of {@link DefaultReactiveHyperLogLogOperations}. - * - * @param template must not be {@literal null}. - * @param serializationContext must not be {@literal null}. - */ - DefaultReactiveHyperLogLogOperations(ReactiveRedisTemplate template, - RedisSerializationContext serializationContext) { - - Assert.notNull(template, "ReactiveRedisTemplate must not be null!"); - Assert.notNull(serializationContext, "RedisSerializationContext must not be null!"); - - this.template = template; - this.serializationContext = serializationContext; - } + private final @NonNull ReactiveRedisTemplate template; + private final @NonNull RedisSerializationContext serializationContext; /* (non-Javadoc) * @see org.springframework.data.redis.core.ReactiveHyperLogLogOperations#add(java.lang.Object, java.lang.Object[]) diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveListOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveListOperations.java index b9d2a7e06..432f1d6ad 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveListOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveListOperations.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -39,26 +41,11 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @since 2.0 */ +@RequiredArgsConstructor class DefaultReactiveListOperations implements ReactiveListOperations { - private final ReactiveRedisTemplate template; - private final RedisSerializationContext serializationContext; - - /** - * Create new instance of {@link DefaultReactiveListOperations}. - * - * @param template must not be {@literal null}. - * @param serializationContext must not be {@literal null}. - */ - DefaultReactiveListOperations(ReactiveRedisTemplate template, - RedisSerializationContext serializationContext) { - - Assert.notNull(template, "ReactiveRedisTemplate must not be null!"); - Assert.notNull(serializationContext, "RedisSerializationContext must not be null!"); - - this.template = template; - this.serializationContext = serializationContext; - } + private final @NonNull ReactiveRedisTemplate template; + private final @NonNull RedisSerializationContext serializationContext; /* (non-Javadoc) * @see org.springframework.data.redis.core.ReactiveListOperations#range(java.lang.Object, long, long) diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveSetOperations.java index e1cfbd88f..e204850f0 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveSetOperations.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -37,26 +39,11 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @since 2.0 */ +@RequiredArgsConstructor class DefaultReactiveSetOperations implements ReactiveSetOperations { - private final ReactiveRedisTemplate template; - private final RedisSerializationContext serializationContext; - - /** - * Creates new {@link DefaultReactiveSetOperations}. - * - * @param template must not be {@literal null}. - * @param serializationContext must not be {@literal null}. - */ - DefaultReactiveSetOperations(ReactiveRedisTemplate template, - RedisSerializationContext serializationContext) { - - Assert.notNull(template, "ReactiveRedisTemplate must not be null!"); - Assert.notNull(serializationContext, "RedisSerializationContext must not be null!"); - - this.template = template; - this.serializationContext = serializationContext; - } + private final @NonNull ReactiveRedisTemplate template; + private final @NonNull RedisSerializationContext serializationContext; /* (non-Javadoc) * @see org.springframework.data.redis.core.ReactiveSetOperations#add(java.lang.Object, java.lang.Object[]) diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveValueOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveValueOperations.java index 977d62384..d3adf2dca 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveValueOperations.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -41,26 +43,11 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @since 2.0 */ +@RequiredArgsConstructor class DefaultReactiveValueOperations implements ReactiveValueOperations { - private final ReactiveRedisTemplate template; - private final RedisSerializationContext serializationContext; - - /** - * Creates new {@link DefaultReactiveValueOperations}. - * - * @param template must not be {@literal null}. - * @param serializationContext must not be {@literal null}. - */ - DefaultReactiveValueOperations(ReactiveRedisTemplate template, - RedisSerializationContext serializationContext) { - - Assert.notNull(template, "ReactiveRedisTemplate must not be null!"); - Assert.notNull(serializationContext, "RedisSerializationContext must not be null!"); - - this.template = template; - this.serializationContext = serializationContext; - } + private final @NonNull ReactiveRedisTemplate template; + private final @NonNull RedisSerializationContext serializationContext; /* (non-Javadoc) * @see org.springframework.data.redis.core.ReactiveValueOperations#set(java.lang.Object, java.lang.Object) 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 80dc51c2a..6d5390de7 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveZSetOperations.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -43,26 +45,11 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @since 2.0 */ +@RequiredArgsConstructor class DefaultReactiveZSetOperations implements ReactiveZSetOperations { - private final ReactiveRedisTemplate template; - private final RedisSerializationContext serializationContext; - - /** - * Creates new {@link DefaultReactiveZSetOperations}. - * - * @param template must not be {@literal null}. - * @param serializationContext must not be {@literal null}. - */ - DefaultReactiveZSetOperations(ReactiveRedisTemplate template, - RedisSerializationContext serializationContext) { - - Assert.notNull(template, "ReactiveRedisTemplate must not be null!"); - Assert.notNull(serializationContext, "RedisSerializationContext must not be null!"); - - this.template = template; - this.serializationContext = serializationContext; - } + private final @NonNull ReactiveRedisTemplate template; + private final @NonNull RedisSerializationContext serializationContext; /* (non-Javadoc) * @see org.springframework.data.redis.core.ReactiveZSetOperations#add(java.lang.Object, java.lang.Object, double) 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 5724a8fed..fea5a05cb 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultZSetOperations.java @@ -153,7 +153,7 @@ class DefaultZSetOperations extends AbstractOperations implements ZS */ @Override public Set rangeByLex(K key, Range range) { - return rangeByLex(key, range, null); + return rangeByLex(key, range, Limit.unlimited()); } /* diff --git a/src/main/java/org/springframework/data/redis/core/HashOperationsEditor.java b/src/main/java/org/springframework/data/redis/core/HashOperationsEditor.java index 746a9559a..b68ec7086 100644 --- a/src/main/java/org/springframework/data/redis/core/HashOperationsEditor.java +++ b/src/main/java/org/springframework/data/redis/core/HashOperationsEditor.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -19,7 +19,7 @@ import java.beans.PropertyEditorSupport; /** * PropertyEditor allowing for easy injection of {@link HashOperations} from {@link RedisOperations}. - * + * * @author Costin Leau */ class HashOperationsEditor extends PropertyEditorSupport { @@ -28,7 +28,7 @@ class HashOperationsEditor extends PropertyEditorSupport { if (value instanceof RedisOperations) { super.setValue(((RedisOperations) value).opsForHash()); } else { - throw new java.lang.IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); + throw new IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); } } } diff --git a/src/main/java/org/springframework/data/redis/core/HyperLogLogOperations.java b/src/main/java/org/springframework/data/redis/core/HyperLogLogOperations.java index b694e005c..acaad8fab 100644 --- a/src/main/java/org/springframework/data/redis/core/HyperLogLogOperations.java +++ b/src/main/java/org/springframework/data/redis/core/HyperLogLogOperations.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2017 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. @@ -23,32 +23,34 @@ public interface HyperLogLogOperations { /** * Adds the given {@literal values} to the {@literal key}. - * + * * @param key must not be {@literal null}. * @param values must not be {@literal null}. - * @return 1 of at least one of the values was added to the key; 0 otherwise. + * @return 1 of at least one of the values was added to the key; 0 otherwise. {@literal null} when used in pipeline / + * transaction. */ Long add(K key, V... values); /** * Gets the current number of elements within the {@literal key}. - * + * * @param keys must not be {@literal null} or {@literal empty}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ Long size(K... keys); /** * Merges all values of given {@literal sourceKeys} into {@literal destination} key. - * + * * @param destination key of HyperLogLog to move source keys into. * @param sourceKeys must not be {@literal null} or {@literal empty}. + * @return {@literal null} when used in pipeline / transaction. */ Long union(K destination, K... sourceKeys); /** * Removes the given {@literal key}. - * + * * @param key must not be {@literal null}. */ void delete(K key); diff --git a/src/main/java/org/springframework/data/redis/core/IndexWriter.java b/src/main/java/org/springframework/data/redis/core/IndexWriter.java index 18e584888..78a04f63a 100644 --- a/src/main/java/org/springframework/data/redis/core/IndexWriter.java +++ b/src/main/java/org/springframework/data/redis/core/IndexWriter.java @@ -26,6 +26,7 @@ import org.springframework.data.redis.core.convert.RedisConverter; import org.springframework.data.redis.core.convert.RemoveIndexedData; import org.springframework.data.redis.core.convert.SimpleIndexedPropertyValue; import org.springframework.data.redis.util.ByteUtils; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -87,11 +88,12 @@ class IndexWriter { * @param key must not be {@literal null}. * @param indexValues can be {@literal null}. */ - public void deleteAndUpdateIndexes(Object key, Iterable indexValues) { + public void deleteAndUpdateIndexes(Object key, @Nullable Iterable indexValues) { createOrUpdateIndexes(key, indexValues, IndexWriteMode.UPDATE); } - private void createOrUpdateIndexes(Object key, Iterable indexValues, IndexWriteMode writeMode) { + private void createOrUpdateIndexes(Object key, @Nullable Iterable indexValues, + IndexWriteMode writeMode) { Assert.notNull(key, "Key must not be null!"); if (indexValues == null) { @@ -104,7 +106,7 @@ class IndexWriter { if (indexValues.iterator().hasNext()) { IndexedData data = indexValues.iterator().next(); - if (data != null && data.getKeyspace() != null) { + if (data != null) { removeKeyFromIndexes(data.getKeyspace(), binKey); } } @@ -240,7 +242,7 @@ class IndexWriter { } } - private byte[] toBytes(Object source) { + private byte[] toBytes(@Nullable Object source) { if (source == null) { return new byte[] {}; diff --git a/src/main/java/org/springframework/data/redis/core/KeyBoundCursor.java b/src/main/java/org/springframework/data/redis/core/KeyBoundCursor.java index 39f42bff2..f97807c11 100644 --- a/src/main/java/org/springframework/data/redis/core/KeyBoundCursor.java +++ b/src/main/java/org/springframework/data/redis/core/KeyBoundCursor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-2017 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. @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import org.springframework.lang.Nullable; + /** * @author Christoph Strobl * @param @@ -26,11 +28,11 @@ public abstract class KeyBoundCursor extends ScanCursor { /** * Crates new {@link ScanCursor} - * + * * @param cursorId * @param options Defaulted to {@link ScanOptions#NONE} if nulled. */ - public KeyBoundCursor(byte[] key, long cursorId, ScanOptions options) { + public KeyBoundCursor(byte[] key, long cursorId, @Nullable ScanOptions options) { super(cursorId, options != null ? options : ScanOptions.NONE); this.key = key; } diff --git a/src/main/java/org/springframework/data/redis/core/ListOperations.java b/src/main/java/org/springframework/data/redis/core/ListOperations.java index 49d0bebe2..0fe026484 100644 --- a/src/main/java/org/springframework/data/redis/core/ListOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ListOperations.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2017 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 - * + * * http://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. @@ -19,9 +19,11 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.TimeUnit; +import org.springframework.lang.Nullable; + /** * Redis list specific operations. - * + * * @author Costin Leau * @author David Liu * @author Thomas Darimont @@ -36,9 +38,10 @@ public interface ListOperations { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LRANGE */ + @Nullable List range(K key, long start, long end); /** @@ -55,9 +58,10 @@ public interface ListOperations { * Get the size of list stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LLEN */ + @Nullable Long size(K key); /** @@ -65,9 +69,10 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSH */ + @Nullable Long leftPush(K key, V value); /** @@ -75,9 +80,10 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param values - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSH */ + @Nullable Long leftPushAll(K key, V... values); /** @@ -85,10 +91,11 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param values must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.5 * @see Redis Documentation: LPUSH */ + @Nullable Long leftPushAll(K key, Collection values); /** @@ -96,9 +103,10 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSHX */ + @Nullable Long leftPushIfPresent(K key, V value); /** @@ -106,9 +114,10 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSH */ + @Nullable Long leftPush(K key, V pivot, V value); /** @@ -116,9 +125,10 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSH */ + @Nullable Long rightPush(K key, V value); /** @@ -126,9 +136,10 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param values - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSH */ + @Nullable Long rightPushAll(K key, V... values); /** @@ -136,10 +147,11 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param values - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.5 * @see Redis Documentation: RPUSH */ + @Nullable Long rightPushAll(K key, Collection values); /** @@ -147,9 +159,10 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSHX */ + @Nullable Long rightPushIfPresent(K key, V value); /** @@ -157,9 +170,10 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSH */ + @Nullable Long rightPush(K key, V pivot, V value); /** @@ -178,9 +192,10 @@ public interface ListOperations { * @param key must not be {@literal null}. * @param count * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LREM */ + @Nullable Long remove(K key, long count, Object value); /** @@ -188,18 +203,20 @@ public interface ListOperations { * * @param key must not be {@literal null}. * @param index - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LINDEX */ + @Nullable V index(K key, long index); /** * Removes and returns first element in list stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return can be {@literal null}. * @see Redis Documentation: LPOP */ + @Nullable V leftPop(K key); /** @@ -209,18 +226,20 @@ public interface ListOperations { * @param key must not be {@literal null}. * @param timeout * @param unit must not be {@literal null}. - * @return + * @return can be {@literal null}. * @see Redis Documentation: BLPOP */ + @Nullable V leftPop(K key, long timeout, TimeUnit unit); /** * Removes and returns last element in list stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return can be {@literal null}. * @see Redis Documentation: RPOP */ + @Nullable V rightPop(K key); /** @@ -230,9 +249,10 @@ public interface ListOperations { * @param key must not be {@literal null}. * @param timeout * @param unit must not be {@literal null}. - * @return + * @return can be {@literal null}. * @see Redis Documentation: BRPOP */ + @Nullable V rightPop(K key, long timeout, TimeUnit unit); /** @@ -240,9 +260,10 @@ public interface ListOperations { * * @param sourceKey must not be {@literal null}. * @param destinationKey must not be {@literal null}. - * @return + * @return can be {@literal null}. * @see Redis Documentation: RPOPLPUSH */ + @Nullable V rightPopAndLeftPush(K sourceKey, K destinationKey); /** @@ -253,9 +274,10 @@ public interface ListOperations { * @param destinationKey must not be {@literal null}. * @param timeout * @param unit must not be {@literal null}. - * @return + * @return can be {@literal null}. * @see Redis Documentation: BRPOPLPUSH */ + @Nullable V rightPopAndLeftPush(K sourceKey, K destinationKey, long timeout, TimeUnit unit); RedisOperations getOperations(); diff --git a/src/main/java/org/springframework/data/redis/core/ListOperationsEditor.java b/src/main/java/org/springframework/data/redis/core/ListOperationsEditor.java index b1a980d25..baefd5cf9 100644 --- a/src/main/java/org/springframework/data/redis/core/ListOperationsEditor.java +++ b/src/main/java/org/springframework/data/redis/core/ListOperationsEditor.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -19,7 +19,7 @@ import java.beans.PropertyEditorSupport; /** * PropertyEditor allowing for easy injection of {@link ListOperations} from {@link RedisOperations}. - * + * * @author Costin Leau */ class ListOperationsEditor extends PropertyEditorSupport { @@ -28,7 +28,7 @@ class ListOperationsEditor extends PropertyEditorSupport { if (value instanceof RedisOperations) { super.setValue(((RedisOperations) value).opsForList()); } else { - throw new java.lang.IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); + throw new IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); } } } diff --git a/src/main/java/org/springframework/data/redis/core/PartialUpdate.java b/src/main/java/org/springframework/data/redis/core/PartialUpdate.java index 18705df34..29702419c 100644 --- a/src/main/java/org/springframework/data/redis/core/PartialUpdate.java +++ b/src/main/java/org/springframework/data/redis/core/PartialUpdate.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -35,12 +36,13 @@ public class PartialUpdate { private final Object id; private final Class target; - private final T value; + private final @Nullable T value; private boolean refreshTtl = false; private final List propertyUpdates = new ArrayList<>(); - private PartialUpdate(Object id, Class target, T value, boolean refreshTtl, List propertyUpdates) { + private PartialUpdate(Object id, Class target, @Nullable T value, boolean refreshTtl, + List propertyUpdates) { this.id = id; this.target = target; @@ -96,6 +98,7 @@ public class PartialUpdate { /** * @return can be {@literal null}. */ + @Nullable public T getValue() { return value; } @@ -187,13 +190,13 @@ public class PartialUpdate { private final UpdateCommand cmd; private final String propertyPath; - private final Object value; + private final @Nullable Object value; private PropertyUpdate(UpdateCommand cmd, String propertyPath) { this(cmd, propertyPath, null); } - private PropertyUpdate(UpdateCommand cmd, String propertyPath, Object value) { + private PropertyUpdate(UpdateCommand cmd, String propertyPath, @Nullable Object value) { this.cmd = cmd; this.propertyPath = propertyPath; @@ -223,6 +226,7 @@ public class PartialUpdate { * * @return can be {@literal null}. */ + @Nullable public Object getValue() { return value; } @@ -232,7 +236,7 @@ public class PartialUpdate { * @author Christoph Strobl * @since 1.8 */ - public static enum UpdateCommand { + public enum UpdateCommand { SET, DEL } } diff --git a/src/main/java/org/springframework/data/redis/core/RedisAccessor.java b/src/main/java/org/springframework/data/redis/core/RedisAccessor.java index a8ab8a716..b7c658046 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisAccessor.java +++ b/src/main/java/org/springframework/data/redis/core/RedisAccessor.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -24,7 +24,7 @@ import org.springframework.util.Assert; /** * Base class for {@link RedisTemplate} defining common properties. Not intended to be used directly. - * + * * @author Costin Leau */ public class RedisAccessor implements InitializingBean { @@ -40,7 +40,7 @@ public class RedisAccessor implements InitializingBean { /** * Returns the connectionFactory. - * + * * @return Returns the connectionFactory. Can be {@literal null} */ @Nullable @@ -48,9 +48,28 @@ public class RedisAccessor implements InitializingBean { return connectionFactory; } + /** + * Returns the required {@link RedisConnectionFactory} or throws {@link IllegalStateException} if the connection + * factory is not set. + * + * @return the associated {@link RedisConnectionFactory}. + * @throws IllegalStateException if the connection factory is not set. + * @since 2.0 + */ + public RedisConnectionFactory getRequiredConnectionFactory() { + + RedisConnectionFactory connectionFactory = getConnectionFactory(); + + if (connectionFactory == null) { + throw new IllegalStateException("RedisConnectionFactory is required"); + } + + return connectionFactory; + } + /** * Sets the connection factory. - * + * * @param connectionFactory The connectionFactory to set. */ public void setConnectionFactory(RedisConnectionFactory connectionFactory) { diff --git a/src/main/java/org/springframework/data/redis/core/RedisCallback.java b/src/main/java/org/springframework/data/redis/core/RedisCallback.java index b889651c0..7db3173a9 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisCallback.java +++ b/src/main/java/org/springframework/data/redis/core/RedisCallback.java @@ -1,12 +1,12 @@ /* - * Copyright 2011-2013 the original author or authors. - * + * Copyright 2011-2017 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 - * + * * http://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. @@ -17,12 +17,13 @@ package org.springframework.data.redis.core; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.lang.Nullable; /** * Callback interface for Redis 'low level' code. To be used with {@link RedisTemplate} execution methods, often as * anonymous classes within a method implementation. Usually, used for chaining several operations together ( * {@code get/set/trim etc...}. - * + * * @author Costin Leau */ public interface RedisCallback { @@ -30,10 +31,11 @@ public interface RedisCallback { /** * Gets called by {@link RedisTemplate} with an active Redis connection. Does not need to care about activating or * closing the connection or handling exceptions. - * + * * @param connection active Redis connection * @return a result object or {@code null} if none * @throws DataAccessException */ + @Nullable T doInRedis(RedisConnection connection) throws DataAccessException; } diff --git a/src/main/java/org/springframework/data/redis/core/RedisClusterCallback.java b/src/main/java/org/springframework/data/redis/core/RedisClusterCallback.java index 327913446..61cf371e5 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisClusterCallback.java +++ b/src/main/java/org/springframework/data/redis/core/RedisClusterCallback.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2017 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. @@ -17,10 +17,11 @@ package org.springframework.data.redis.core; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisClusterConnection; +import org.springframework.lang.Nullable; /** * Callback interface for low level operations executed against a clustered Redis environment. - * + * * @author Christoph Strobl * @since 1.7 * @param @@ -30,10 +31,11 @@ public interface RedisClusterCallback { /** * Gets called by {@link RedisClusterTemplate} with an active Redis connection. Does not need to care about activating * or closing the connection or handling exceptions. - * + * * @param connection never {@literal null}. * @return * @throws DataAccessException */ + @Nullable T doInRedis(RedisClusterConnection connection) throws DataAccessException; } 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 6606cec24..4219c2de3 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisCommand.java +++ b/src/main/java/org/springframework/data/redis/core/RedisCommand.java @@ -239,11 +239,11 @@ public enum RedisCommand { return Collections.unmodifiableMap(map); } - private RedisCommand(String mode, int minArgs) { + RedisCommand(String mode, int minArgs) { this(mode, minArgs, -1); } - private RedisCommand(String mode, int minArgs, int maxArgs) { + RedisCommand(String mode, int minArgs, int maxArgs) { if (StringUtils.hasText(mode)) { this.read = mode.toLowerCase().indexOf('r') > -1; @@ -262,11 +262,11 @@ public enum RedisCommand { * @param maxArgs * @param alias */ - private RedisCommand(String mode, int minArgs, int maxArgs, String... alias) { + RedisCommand(String mode, int minArgs, int maxArgs, String... alias) { this(mode, minArgs, maxArgs); - if (alias != null && alias.length > 0) { + if (alias.length > 0) { this.alias.addAll(Arrays.asList(alias)); } } 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 002aa1737..dbf7004a6 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisConnectionUtils.java +++ b/src/main/java/org/springframework/data/redis/core/RedisConnectionUtils.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2016 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 - * + * * http://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. @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core; +import lombok.RequiredArgsConstructor; + import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -26,6 +28,7 @@ import org.springframework.aop.framework.ProxyFactory; import org.springframework.cglib.proxy.MethodProxy; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.lang.Nullable; import org.springframework.transaction.support.ResourceHolder; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationAdapter; @@ -35,7 +38,7 @@ import org.springframework.util.Assert; /** * Helper class featuring {@link RedisConnection} handling, allowing for reuse of instances within * 'transactions'/scopes. - * + * * @author Costin Leau * @author Christoph Strobl * @author Thomas Darimont @@ -47,7 +50,7 @@ public abstract class RedisConnectionUtils { /** * Binds a new Redis connection (from the given factory) to the current thread, if none is already bound. - * + * * @param factory connection factory * @return a new Redis connection without transaction support. */ @@ -58,7 +61,7 @@ public abstract class RedisConnectionUtils { /** * Binds a new Redis connection (from the given factory) to the current thread, if none is already bound and enables * transaction support if {@code enableTranactionSupport} is set to {@literal true}. - * + * * @param factory connection factory * @param enableTranactionSupport * @return a new Redis connection with transaction support if requested. @@ -71,7 +74,7 @@ public abstract class RedisConnectionUtils { * Gets a Redis connection from the given factory. Is aware of and will return any existing corresponding connections * bound to the current thread, for example when using a transaction manager. Will always create a new connection * otherwise. - * + * * @param factory connection factory for creating the connection * @return an active Redis connection without transaction management. */ @@ -83,7 +86,7 @@ public abstract class RedisConnectionUtils { * Gets a Redis connection from the given factory. Is aware of and will return any existing corresponding connections * bound to the current thread, for example when using a transaction manager. Will always create a new connection * otherwise. - * + * * @param factory connection factory for creating the connection * @param enableTranactionSupport * @return an active Redis connection with transaction management if requested. @@ -96,7 +99,7 @@ public abstract class RedisConnectionUtils { * Gets a Redis connection. Is aware of and will return any existing corresponding connections bound to the current * thread, for example when using a transaction manager. Will create a new Connection otherwise, if * {@code allowCreate} is true. - * + * * @param factory connection factory for creating the connection * @param allowCreate whether a new (unbound) connection should be created when no connection can be found for the * current thread @@ -159,8 +162,8 @@ public abstract class RedisConnectionUtils { RedisConnection conn = connHolder.getConnection(); conn.multi(); - TransactionSynchronizationManager.registerSynchronization(new RedisTransactionSynchronizer(connHolder, conn, - factory)); + TransactionSynchronizationManager + .registerSynchronization(new RedisTransactionSynchronizer(connHolder, conn, factory)); } } } @@ -181,11 +184,11 @@ public abstract class RedisConnectionUtils { /** * Closes the given connection, created via the given factory if not managed externally (i.e. not bound to the * thread). - * - * @param conn the Redis connection to close - * @param factory the Redis factory that the connection was created with + * + * @param conn the Redis connection to close. + * @param factory the Redis factory that the connection was created with. */ - public static void releaseConnection(RedisConnection conn, RedisConnectionFactory factory) { + public static void releaseConnection(@Nullable RedisConnection conn, RedisConnectionFactory factory) { if (conn == null) { return; @@ -202,8 +205,7 @@ public abstract class RedisConnectionUtils { // release transactional/read-only and non-transactional/non-bound connections. // transactional connections for read-only transactions get no synchronizer registered - if (isConnectionTransactional(conn, factory) - && TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { + if (isConnectionTransactional(conn, factory) && TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { unbindConnection(factory); } else if (!isConnectionTransactional(conn, factory)) { if (log.isDebugEnabled()) { @@ -215,7 +217,7 @@ public abstract class RedisConnectionUtils { /** * Unbinds and closes the connection (if any) associated with the given factory. - * + * * @param factory Redis factory */ public static void unbindConnection(RedisConnectionFactory factory) { @@ -223,34 +225,35 @@ public abstract class RedisConnectionUtils { RedisConnectionHolder connHolder = (RedisConnectionHolder) TransactionSynchronizationManager .unbindResourceIfPossible(factory); - if (connHolder != null) { - if (connHolder.isTransactionSyncronisationActive()) { - if (log.isDebugEnabled()) { - log.debug("Redis Connection will be closed when outer transaction finished."); - } - } else { - if (log.isDebugEnabled()) { - log.debug("Closing bound connection."); - } - RedisConnection connection = connHolder.getConnection(); - connection.close(); - } + if (connHolder == null) { + return; } + if (connHolder.isTransactionSyncronisationActive()) { + if (log.isDebugEnabled()) { + log.debug("Redis Connection will be closed when outer transaction finished."); + } + } else { + if (log.isDebugEnabled()) { + log.debug("Closing bound connection."); + } + RedisConnection connection = connHolder.getConnection(); + connection.close(); + } } /** * Return whether the given Redis connection is transactional, that is, bound to the current thread by Spring's * transaction facilities. - * + * * @param conn Redis connection to check * @param connFactory Redis connection factory that the connection was created with * @return whether the connection is transactional or not */ public static boolean isConnectionTransactional(RedisConnection conn, RedisConnectionFactory connFactory) { - if (connFactory == null) { - return false; - } + + Assert.notNull(connFactory, "No RedisConnectionFactory specified"); + RedisConnectionHolder connHolder = (RedisConnectionHolder) TransactionSynchronizationManager .getResource(connFactory); @@ -260,31 +263,17 @@ public abstract class RedisConnectionUtils { /** * A {@link TransactionSynchronizationAdapter} that makes sure that the associated RedisConnection is released after * the transaction completes. - * + * * @author Christoph Strobl * @author Thomas Darimont */ + @RequiredArgsConstructor private static class RedisTransactionSynchronizer extends TransactionSynchronizationAdapter { private final RedisConnectionHolder connHolder; private final RedisConnection connection; private final RedisConnectionFactory factory; - /** - * Creates a new {@link RedisTransactionSynchronizer}. - * - * @param connHolder - * @param connection - * @param factory - */ - private RedisTransactionSynchronizer(RedisConnectionHolder connHolder, RedisConnection connection, - RedisConnectionFactory factory) { - - this.connHolder = connHolder; - this.connection = connection; - this.factory = factory; - } - @Override public void afterCompletion(int status) { @@ -317,8 +306,8 @@ public abstract class RedisConnectionUtils { * @author Christoph Strobl * @since 1.3 */ - static class ConnectionSplittingInterceptor implements MethodInterceptor, - org.springframework.cglib.proxy.MethodInterceptor { + static class ConnectionSplittingInterceptor + implements MethodInterceptor, org.springframework.cglib.proxy.MethodInterceptor { private final RedisConnectionFactory factory; diff --git a/src/main/java/org/springframework/data/redis/core/RedisKeyExpiredEvent.java b/src/main/java/org/springframework/data/redis/core/RedisKeyExpiredEvent.java index 2795a9f7b..4768af35a 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisKeyExpiredEvent.java +++ b/src/main/java/org/springframework/data/redis/core/RedisKeyExpiredEvent.java @@ -16,14 +16,16 @@ package org.springframework.data.redis.core; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import org.springframework.context.ApplicationEvent; import org.springframework.data.redis.util.ByteUtils; +import org.springframework.lang.Nullable; /** * {@link RedisKeyExpiredEvent} is Redis specific {@link ApplicationEvent} published when a specific key in Redis * expires. It might but must not hold the expired value itself next to the key. - * + * * @author Christoph Strobl * @since 1.7 */ @@ -32,14 +34,14 @@ public class RedisKeyExpiredEvent extends RedisKeyspaceEvent { /** * Use {@literal UTF-8} as default charset. */ - public static final Charset CHARSET = Charset.forName("UTF-8"); + public static final Charset CHARSET = StandardCharsets.UTF_8; private final byte[][] args; - private final Object value; + private final @Nullable Object value; /** * Creates new {@link RedisKeyExpiredEvent}. - * + * * @param key */ public RedisKeyExpiredEvent(byte[] key) { @@ -52,7 +54,7 @@ public class RedisKeyExpiredEvent extends RedisKeyspaceEvent { * @param key * @param value */ - public RedisKeyExpiredEvent(byte[] key, Object value) { + public RedisKeyExpiredEvent(byte[] key, @Nullable Object value) { this(null, key, value); } @@ -64,7 +66,7 @@ public class RedisKeyExpiredEvent extends RedisKeyspaceEvent { * @param value * @since 1.8 */ - public RedisKeyExpiredEvent(String channel, byte[] key, Object value) { + public RedisKeyExpiredEvent(@Nullable String channel, byte[] key, @Nullable Object value) { super(channel, key); args = ByteUtils.split(key, ':'); @@ -73,7 +75,7 @@ public class RedisKeyExpiredEvent extends RedisKeyspaceEvent { /** * Gets the keyspace in which the expiration occured. - * + * * @return {@literal null} if it could not be determined. */ public String getKeyspace() { @@ -87,7 +89,7 @@ public class RedisKeyExpiredEvent extends RedisKeyspaceEvent { /** * Get the expired objects id; - * + * * @return */ public byte[] getId() { @@ -96,9 +98,10 @@ public class RedisKeyExpiredEvent extends RedisKeyspaceEvent { /** * Get the expired Object - * + * * @return {@literal null} if not present. */ + @Nullable public Object getValue() { return value; } @@ -109,7 +112,9 @@ public class RedisKeyExpiredEvent extends RedisKeyspaceEvent { */ @Override public String toString() { - return "RedisKeyExpiredEvent [keyspace=" + getKeyspace() + ", id=" + getId() + "]"; + + byte[] id = getId(); + return "RedisKeyExpiredEvent [keyspace=" + getKeyspace() + ", id=" + (id == null ? null : new String(id)) + "]"; } } 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 29875d1b5..6911b03a6 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java +++ b/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java @@ -155,7 +155,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter * @since 2.0 */ public RedisKeyValueAdapter(RedisOperations redisOps, RedisMappingContext mappingContext, - org.springframework.data.convert.CustomConversions customConversions) { + @Nullable org.springframework.data.convert.CustomConversions customConversions) { super(new RedisQueryEngine()); @@ -277,6 +277,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter * (non-Javadoc) * @see org.springframework.data.keyvalue.core.KeyValueAdapter#get(java.lang.Object, java.lang.String) */ + @Nullable @Override public Object get(Object id, String keyspace) { return get(id, keyspace, Object.class); @@ -286,6 +287,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter * (non-Javadoc) * @see org.springframework.data.keyvalue.core.KeyValueAdapter#get(java.lang.Object, java.lang.String, java.lang.Class) */ + @Nullable @Override public T get(Object id, String keyspace, Class type) { @@ -365,7 +367,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter } offset = Math.max(0, offset); - if (offset >= 0 && rows > 0) { + if (rows > 0) { keys = keys.subList((int) offset, Math.min((int) offset + rows, keys.size())); } @@ -542,6 +544,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter * @see RedisOperations#execute(RedisCallback) * @return */ + @Nullable public T execute(RedisCallback callback) { return redisOps.execute(callback); } @@ -591,8 +594,9 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter * @param target * @return */ + @Nullable @SuppressWarnings({ "unchecked", "rawtypes" }) - private T readBackTimeToLiveIfSet(byte[] key, T target) { + private T readBackTimeToLiveIfSet(@Nullable byte[] key, @Nullable T target) { if (target == null || key == null) { return target; diff --git a/src/main/java/org/springframework/data/redis/core/RedisKeyspaceEvent.java b/src/main/java/org/springframework/data/redis/core/RedisKeyspaceEvent.java index fee229eb0..bb88270b1 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisKeyspaceEvent.java +++ b/src/main/java/org/springframework/data/redis/core/RedisKeyspaceEvent.java @@ -16,16 +16,17 @@ package org.springframework.data.redis.core; import org.springframework.context.ApplicationEvent; +import org.springframework.lang.Nullable; /** * Redis specific {@link ApplicationEvent} published when a key expires in Redis. - * + * * @author Christoph Strobl * @since 1.7 */ public class RedisKeyspaceEvent extends ApplicationEvent { - private final String channel; + private final @Nullable String channel; /** * Creates new {@link RedisKeyspaceEvent}. @@ -43,7 +44,7 @@ public class RedisKeyspaceEvent extends ApplicationEvent { * @param key The key that expired. Must not be {@literal null}. * @since 1.8 */ - public RedisKeyspaceEvent(String channel, byte[] key) { + public RedisKeyspaceEvent(@Nullable String channel, byte[] key) { super(key); this.channel = channel; @@ -58,10 +59,10 @@ public class RedisKeyspaceEvent extends ApplicationEvent { } /** - * * @return can be {@literal null}. * @since 1.8 */ + @Nullable public String getChannel() { return this.channel; } 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 9c43880ef..6eb3c6260 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisOperations.java +++ b/src/main/java/org/springframework/data/redis/core/RedisOperations.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2017 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 - * + * * http://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. @@ -33,7 +33,7 @@ import org.springframework.lang.Nullable; /** * Interface that specified a basic set of Redis operations, implemented by {@link RedisTemplate}. Not often used but a * useful option for extensibility and testability (as it can be easily mocked or stubbed). - * + * * @author Costin Leau * @author Christoph Strobl * @author Ninad Divadkar @@ -49,7 +49,7 @@ public interface RedisOperations { * for the Redis storage. Note: Callback code is not supposed to handle transactions itself! Use an appropriate * transaction manager. Generally, callback code must not touch any Connection lifecycle methods, like close, to let * the template do its work. - * + * * @param return type * @param action callback object that specifies the Redis action. Must not be {@literal null}. * @return a result object returned by the action or null @@ -60,7 +60,7 @@ public interface RedisOperations { /** * Executes a Redis session. Allows multiple operations to be executed in the same session enabling 'transactional' * capabilities through {@link #multi()} and {@link #watch(Collection)} operations. - * + * * @param return type * @param session session callback. Must not be {@literal null}. * @return result object returned by the action or null @@ -72,7 +72,7 @@ public interface RedisOperations { * Executes the given action object on a pipelined connection, returning the results. Note that the callback * cannot return a non-null value as it gets overwritten by the pipeline. This method will use the default * serializers to deserialize results - * + * * @param action callback object to execute * @return list of objects returned by the pipeline */ @@ -81,7 +81,7 @@ public interface RedisOperations { /** * Executes the given action object on a pipelined connection, returning the results using a dedicated serializer. * Note that the callback cannot return a non-null value as it gets overwritten by the pipeline. - * + * * @param action callback object to execute * @param resultSerializer The Serializer to use for individual values or Collections of values. If any returned * values are hashes, this serializer will be used to deserialize both the key and value @@ -92,7 +92,7 @@ public interface RedisOperations { /** * Executes the given Redis session on a pipelined connection. Allows transactions to be pipelined. Note that the * callback cannot return a non-null value as it gets overwritten by the pipeline. - * + * * @param session Session callback * @return list of objects returned by the pipeline */ @@ -102,7 +102,7 @@ public interface RedisOperations { * Executes the given Redis session on a pipelined connection, returning the results using a dedicated serializer. * Allows transactions to be pipelined. Note that the callback cannot return a non-null value as it gets * overwritten by the pipeline. - * + * * @param session Session callback * @param resultSerializer * @return list of objects returned by the pipeline @@ -111,7 +111,7 @@ public interface RedisOperations { /** * Executes the given {@link RedisScript} - * + * * @param script The script to execute * @param keys Any keys that need to be passed to the script * @param args Any args that need to be passed to the script @@ -124,7 +124,7 @@ public interface RedisOperations { /** * Executes the given {@link RedisScript}, using the provided {@link RedisSerializer}s to serialize the script * arguments and result. - * + * * @param script The script to execute * @param argsSerializer The {@link RedisSerializer} to use for serializing args * @param resultSerializer The {@link RedisSerializer} to use for serializing the script return value @@ -159,6 +159,7 @@ public interface RedisOperations { * @return * @see Redis Documentation: EXISTS */ + @Nullable Boolean hasKey(K key); /** @@ -434,7 +435,7 @@ public interface RedisOperations { /** * /** Request information and statistics about connected clients. - * + * * @return {@link List} of {@link RedisClientInfo} objects. * @since 1.3 */ @@ -485,14 +486,14 @@ public interface RedisOperations { // operation types /** * Returns the operations performed on simple values (or Strings in Redis terminology). - * + * * @return value operations */ ValueOperations opsForValue(); /** * Returns the operations performed on simple values (or Strings in Redis terminology) bound to the given key. - * + * * @param key Redis key * @return value operations bound to the given key */ @@ -500,14 +501,14 @@ public interface RedisOperations { /** * Returns the operations performed on list values. - * + * * @return list operations */ ListOperations opsForList(); /** * Returns the operations performed on list values bound to the given key. - * + * * @param key Redis key * @return list operations bound to the given key */ @@ -515,14 +516,14 @@ public interface RedisOperations { /** * Returns the operations performed on set values. - * + * * @return set operations */ SetOperations opsForSet(); /** * Returns the operations performed on set values bound to the given key. - * + * * @param key Redis key * @return set operations bound to the given key */ @@ -530,7 +531,7 @@ public interface RedisOperations { /** * Returns the operations performed on zset values (also known as sorted sets). - * + * * @return zset operations */ ZSetOperations opsForZSet(); @@ -543,7 +544,7 @@ public interface RedisOperations { /** * Returns the operations performed on zset values (also known as sorted sets) bound to the given key. - * + * * @param key Redis key * @return zset operations bound to the given key. */ @@ -551,7 +552,7 @@ public interface RedisOperations { /** * Returns the operations performed on hash values. - * + * * @param hash key (or field) type * @param hash value type * @return hash operations @@ -560,7 +561,7 @@ public interface RedisOperations { /** * Returns the operations performed on hash values bound to the given key. - * + * * @param hash key (or field) type * @param hash value type * @param key Redis key @@ -587,7 +588,7 @@ public interface RedisOperations { /** * Returns the cluster specific operations interface. - * + * * @return never {@literal null}. * @since 1.7 */ diff --git a/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java b/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java index 25f1d17c3..0e9160915 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java +++ b/src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java @@ -37,6 +37,7 @@ import org.springframework.data.redis.repository.query.RedisOperationChain; import org.springframework.data.redis.repository.query.RedisOperationChain.NearPath; import org.springframework.data.redis.repository.query.RedisOperationChain.PathAndValue; import org.springframework.data.redis.util.ByteUtils; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; /** @@ -63,7 +64,7 @@ class RedisQueryEngine extends QueryEngine criteriaAccessor, - SortAccessor> sortAccessor) { + @Nullable SortAccessor> sortAccessor) { super(criteriaAccessor, sortAccessor); } 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 6428c5592..5715f7367 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -92,10 +92,10 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation private @Nullable RedisSerializer defaultSerializer; private @Nullable ClassLoader classLoader; - @SuppressWarnings("rawtypes") private RedisSerializer keySerializer = null; - @SuppressWarnings("rawtypes") private RedisSerializer valueSerializer = null; - @SuppressWarnings("rawtypes") private RedisSerializer hashKeySerializer = null; - @SuppressWarnings("rawtypes") private RedisSerializer hashValueSerializer = null; + @SuppressWarnings("rawtypes") private @Nullable RedisSerializer keySerializer = null; + @SuppressWarnings("rawtypes") private @Nullable RedisSerializer valueSerializer = null; + @SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashKeySerializer = null; + @SuppressWarnings("rawtypes") private @Nullable RedisSerializer hashValueSerializer = null; private RedisSerializer stringSerializer = new StringRedisSerializer(); private @Nullable ScriptExecutor scriptExecutor; @@ -200,7 +200,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it"); Assert.notNull(action, "Callback object must not be null"); - RedisConnectionFactory factory = getConnectionFactory(); + RedisConnectionFactory factory = getRequiredConnectionFactory(); RedisConnection conn = null; try { @@ -245,7 +245,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it"); Assert.notNull(session, "Callback object must not be null"); - RedisConnectionFactory factory = getConnectionFactory(); + RedisConnectionFactory factory = getRequiredConnectionFactory(); // bind connection RedisConnectionUtils.bindConnection(factory, enableTransactionSupport); try { @@ -260,7 +260,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * @see org.springframework.data.redis.core.RedisOperations#executePipelined(org.springframework.data.redis.core.SessionCallback) */ @Override - public List executePipelined(final SessionCallback session) { + public List executePipelined(SessionCallback session) { return executePipelined(session, valueSerializer); } @@ -269,12 +269,12 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * @see org.springframework.data.redis.core.RedisOperations#executePipelined(org.springframework.data.redis.core.SessionCallback, org.springframework.data.redis.serializer.RedisSerializer) */ @Override - public List executePipelined(final SessionCallback session, final RedisSerializer resultSerializer) { + public List executePipelined(SessionCallback session, @Nullable RedisSerializer resultSerializer) { Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it"); Assert.notNull(session, "Callback object must not be null"); - RedisConnectionFactory factory = getConnectionFactory(); + RedisConnectionFactory factory = getRequiredConnectionFactory(); // bind connection RedisConnectionUtils.bindConnection(factory, enableTransactionSupport); try { @@ -306,7 +306,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * @see org.springframework.data.redis.core.RedisOperations#executePipelined(org.springframework.data.redis.core.RedisCallback) */ @Override - public List executePipelined(final RedisCallback action) { + public List executePipelined(RedisCallback action) { return executePipelined(action, valueSerializer); } @@ -315,7 +315,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * @see org.springframework.data.redis.core.RedisOperations#executePipelined(org.springframework.data.redis.core.RedisCallback, org.springframework.data.redis.serializer.RedisSerializer) */ @Override - public List executePipelined(final RedisCallback action, final RedisSerializer resultSerializer) { + public List executePipelined(RedisCallback action, @Nullable RedisSerializer resultSerializer) { return execute((RedisCallback>) connection -> { connection.openPipeline(); @@ -366,7 +366,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it"); Assert.notNull(callback, "Callback object must not be null"); - RedisConnectionFactory factory = getConnectionFactory(); + RedisConnectionFactory factory = getRequiredConnectionFactory(); RedisConnection connection = preProcessConnection(RedisConnectionUtils.doGetConnection(factory, true, false, false), false); @@ -394,7 +394,8 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation return connection; } - protected T postProcessResult(T result, RedisConnection conn, boolean existingConnection) { + @Nullable + protected T postProcessResult(@Nullable T result, RedisConnection conn, boolean existingConnection) { return result; } @@ -419,7 +420,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } /** - * @return Whether or not the default serializer should be used. If not, any serializers not explicilty set will + * @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() { @@ -428,7 +429,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation /** * @param enableDefaultSerializer Whether or not the default serializer should be used. If not, any serializers not - * explicilty set will remain null and values will not be serialized or deserialized. + * explicitly set will remain null and values will not be serialized or deserialized. */ public void setEnableDefaultSerializer(boolean enableDefaultSerializer) { this.enableDefaultSerializer = enableDefaultSerializer; @@ -596,8 +597,10 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } @SuppressWarnings({ "unchecked", "rawtypes" }) - private List deserializeMixedResults(List rawValues, RedisSerializer valueSerializer, - RedisSerializer hashKeySerializer, RedisSerializer hashValueSerializer) { + @Nullable + private List deserializeMixedResults(@Nullable List rawValues, + @Nullable RedisSerializer valueSerializer, @Nullable RedisSerializer hashKeySerializer, + @Nullable RedisSerializer hashValueSerializer) { if (rawValues == null) { return null; @@ -625,7 +628,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } @SuppressWarnings({ "rawtypes", "unchecked" }) - private Set deserializeSet(Set rawSet, RedisSerializer valueSerializer) { + private Set deserializeSet(Set rawSet, @Nullable RedisSerializer valueSerializer) { if (rawSet.isEmpty()) { return rawSet; @@ -643,7 +646,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } @SuppressWarnings({ "unchecked", "rawtypes" }) - private Set> convertTupleValues(Set rawValues, RedisSerializer valueSerializer) { + private Set> convertTupleValues(Set rawValues, @Nullable RedisSerializer valueSerializer) { Set> set = new LinkedHashSet<>(rawValues.size()); for (Tuple rawValue : rawValues) { @@ -672,7 +675,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation public List exec() { List results = execRaw(); - if (getConnectionFactory().getConvertPipelineAndTxResults()) { + if (getRequiredConnectionFactory().getConvertPipelineAndTxResults()) { return deserializeMixedResults(results, valueSerializer, hashKeySerializer, hashValueSerializer); } else { return results; @@ -1033,7 +1036,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * @see org.springframework.data.redis.core.RedisOperations#sort(org.springframework.data.redis.core.query.SortQuery, org.springframework.data.redis.serializer.RedisSerializer) */ @Override - public List sort(SortQuery query, RedisSerializer resultSerializer) { + public List sort(SortQuery query, @Nullable RedisSerializer resultSerializer) { byte[] rawKey = rawKey(query.getKey()); SortParameters params = QueryUtils.convertQuery(query, stringSerializer); @@ -1058,7 +1061,8 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * @see org.springframework.data.redis.core.RedisOperations#sort(org.springframework.data.redis.core.query.SortQuery, org.springframework.data.redis.core.BulkMapper, org.springframework.data.redis.serializer.RedisSerializer) */ @Override - public List sort(SortQuery query, BulkMapper bulkMapper, RedisSerializer resultSerializer) { + public List sort(SortQuery query, BulkMapper bulkMapper, + @Nullable RedisSerializer resultSerializer) { List values = sort(query, resultSerializer); diff --git a/src/main/java/org/springframework/data/redis/core/ScanCursor.java b/src/main/java/org/springframework/data/redis/core/ScanCursor.java index 2dd324cd1..ea809f57d 100644 --- a/src/main/java/org/springframework/data/redis/core/ScanCursor.java +++ b/src/main/java/org/springframework/data/redis/core/ScanCursor.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2015 the original author or authors. + * Copyright 2014-2017 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. @@ -21,25 +21,27 @@ import java.util.Iterator; import java.util.NoSuchElementException; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; /** * Redis client agnostic {@link Cursor} implementation continuously loading additional results from Redis server until * reaching its starting point {@code zero}.
* Note: Please note that the {@link ScanCursor} has to be initialized ({@link #open()} prior to usage. - * + * * @author Christoph Strobl * @author Thomas Darimont * @author Duobiao Ou + * @author Marl Paluch * @param * @since 1.4 */ public abstract class ScanCursor implements Cursor { - private CursorState state; + private @Nullable CursorState state; private long cursorId; - private Iterator delegate; - private final ScanOptions scanOptions; + private @Nullable Iterator delegate; + private @Nullable final ScanOptions scanOptions; private long position; /** @@ -51,7 +53,7 @@ public abstract class ScanCursor implements Cursor { /** * Crates new {@link ScanCursor} with {@code id=0}. - * + * * @param options */ public ScanCursor(ScanOptions options) { @@ -60,7 +62,7 @@ public abstract class ScanCursor implements Cursor { /** * Crates new {@link ScanCursor} with {@link ScanOptions#NONE} - * + * * @param cursorId */ public ScanCursor(long cursorId) { @@ -69,7 +71,7 @@ public abstract class ScanCursor implements Cursor { /** * Crates new {@link ScanCursor} - * + * * @param cursorId * @param options Defaulted to {@link ScanOptions#NONE} if nulled. */ @@ -90,7 +92,7 @@ public abstract class ScanCursor implements Cursor { /** * Performs the actual scan command using the native client implementation. The given {@literal options} are never * {@code null}. - * + * * @param cursorId * @param options * @return @@ -114,7 +116,7 @@ public abstract class ScanCursor implements Cursor { /** * Customization hook when calling {@link #open()}. - * + * * @param cursorId */ protected void doOpen(long cursorId) { @@ -208,7 +210,7 @@ public abstract class ScanCursor implements Cursor { /** * Fetch the next item from the underlying {@link Iterable}. - * + * * @param source * @return */ diff --git a/src/main/java/org/springframework/data/redis/core/ScanIteration.java b/src/main/java/org/springframework/data/redis/core/ScanIteration.java index 444fa747d..4659fbfff 100644 --- a/src/main/java/org/springframework/data/redis/core/ScanIteration.java +++ b/src/main/java/org/springframework/data/redis/core/ScanIteration.java @@ -20,11 +20,14 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; +import org.springframework.lang.Nullable; + /** * {@link ScanIteration} holds the values contained in Redis {@literal Multibulk reply} on exectuting {@literal SCAN} * command. * * @author Christoph Strobl + * @author Mark Paluch * @since 1.4 */ public class ScanIteration implements Iterable { @@ -36,10 +39,10 @@ public class ScanIteration implements Iterable { * @param cursorId * @param items */ - public ScanIteration(long cursorId, Collection items) { + public ScanIteration(long cursorId, @Nullable Collection items) { this.cursorId = cursorId; - this.items = (items != null ? new ArrayList<>(items) : Collections. emptyList()); + this.items = (items != null ? new ArrayList<>(items) : Collections.emptyList()); } /** diff --git a/src/main/java/org/springframework/data/redis/core/SessionCallback.java b/src/main/java/org/springframework/data/redis/core/SessionCallback.java index 490aa40e1..bfc7bc13c 100644 --- a/src/main/java/org/springframework/data/redis/core/SessionCallback.java +++ b/src/main/java/org/springframework/data/redis/core/SessionCallback.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -16,20 +16,22 @@ package org.springframework.data.redis.core; import org.springframework.dao.DataAccessException; +import org.springframework.lang.Nullable; /** * Callback executing all operations against a surrogate 'session' (basically against the same underlying Redis * connection). Allows 'transactions' to take place through the use of multi/discard/exec/watch/unwatch commands. - * + * * @author Costin Leau */ public interface SessionCallback { /** * Executes all the given operations inside the same session. - * + * * @param operations Redis operations * @return return value */ + @Nullable T execute(RedisOperations operations) throws DataAccessException; } diff --git a/src/main/java/org/springframework/data/redis/core/SetOperations.java b/src/main/java/org/springframework/data/redis/core/SetOperations.java index 00c119f43..c6e7672c4 100644 --- a/src/main/java/org/springframework/data/redis/core/SetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/SetOperations.java @@ -19,6 +19,8 @@ import java.util.Collection; import java.util.List; import java.util.Set; +import org.springframework.lang.Nullable; + /** * Redis set specific operations. * @@ -33,9 +35,10 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param values - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SADD */ + @Nullable Long add(K key, V... values); /** @@ -43,18 +46,20 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param values - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SREM */ + @Nullable Long remove(K key, Object... values); /** * Remove and return a random member from set at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SPOP */ + @Nullable V pop(K key); /** @@ -62,10 +67,11 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param count number of random members to pop from the set. - * @return empty {@link List} if key does not exist. Never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SPOP * @since 2.0 */ + @Nullable List pop(K key, long count); /** @@ -74,18 +80,20 @@ public interface SetOperations { * @param key must not be {@literal null}. * @param value * @param destKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SMOVE */ + @Nullable Boolean move(K key, V value, K destKey); /** * Get size of set at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SCARD */ + @Nullable Long size(K key); /** @@ -93,9 +101,10 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param o - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SISMEMBER */ + @Nullable Boolean isMember(K key, Object o); /** @@ -103,9 +112,10 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param otherKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SINTER */ + @Nullable Set intersect(K key, K otherKey); /** @@ -113,9 +123,10 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param otherKeys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SINTER */ + @Nullable Set intersect(K key, Collection otherKeys); /** @@ -124,9 +135,10 @@ public interface SetOperations { * @param key must not be {@literal null}. * @param otherKey must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SINTERSTORE */ + @Nullable Long intersectAndStore(K key, K otherKey, K destKey); /** @@ -135,9 +147,10 @@ public interface SetOperations { * @param key must not be {@literal null}. * @param otherKeys must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SINTERSTORE */ + @Nullable Long intersectAndStore(K key, Collection otherKeys, K destKey); /** @@ -145,9 +158,10 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param otherKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SUNION */ + @Nullable Set union(K key, K otherKey); /** @@ -155,9 +169,10 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param otherKeys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SUNION */ + @Nullable Set union(K key, Collection otherKeys); /** @@ -166,9 +181,10 @@ public interface SetOperations { * @param key must not be {@literal null}. * @param otherKey must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SUNIONSTORE */ + @Nullable Long unionAndStore(K key, K otherKey, K destKey); /** @@ -177,9 +193,10 @@ public interface SetOperations { * @param key must not be {@literal null}. * @param otherKeys must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SUNIONSTORE */ + @Nullable Long unionAndStore(K key, Collection otherKeys, K destKey); /** @@ -187,9 +204,10 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param otherKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SDIFF */ + @Nullable Set difference(K key, K otherKey); /** @@ -197,9 +215,10 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param otherKeys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SDIFF */ + @Nullable Set difference(K key, Collection otherKeys); /** @@ -208,9 +227,10 @@ public interface SetOperations { * @param key must not be {@literal null}. * @param otherKey must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SDIFFSTORE */ + @Nullable Long differenceAndStore(K key, K otherKey, K destKey); /** @@ -219,25 +239,27 @@ public interface SetOperations { * @param key must not be {@literal null}. * @param otherKeys must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SDIFFSTORE */ + @Nullable Long differenceAndStore(K key, Collection otherKeys, K destKey); /** * Get all elements of set at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SMEMBERS */ + @Nullable Set members(K key); /** * Get random element from set at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SRANDMEMBER */ V randomMember(K key); @@ -251,6 +273,7 @@ public interface SetOperations { * @throws IllegalArgumentException if count is negative. * @see Redis Documentation: SRANDMEMBER */ + @Nullable Set distinctRandomMembers(K key, long count); /** @@ -258,10 +281,11 @@ public interface SetOperations { * * @param key must not be {@literal null}. * @param count nr of members to return. - * @return empty {@link List} if {@code key} does not exist. + * @return empty {@link List} if {@code key} does not exist or {@literal null} when used in pipeline / transaction. * @throws IllegalArgumentException if count is negative. * @see Redis Documentation: SRANDMEMBER */ + @Nullable List randomMembers(K key, long count); /** diff --git a/src/main/java/org/springframework/data/redis/core/SetOperationsEditor.java b/src/main/java/org/springframework/data/redis/core/SetOperationsEditor.java index 7ec3e30f4..0829c0cbc 100644 --- a/src/main/java/org/springframework/data/redis/core/SetOperationsEditor.java +++ b/src/main/java/org/springframework/data/redis/core/SetOperationsEditor.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -19,7 +19,7 @@ import java.beans.PropertyEditorSupport; /** * PropertyEditor allowing for easy injection of {@link SetOperations} from {@link RedisOperations}. - * + * * @author Costin Leau */ class SetOperationsEditor extends PropertyEditorSupport { @@ -28,7 +28,7 @@ class SetOperationsEditor extends PropertyEditorSupport { if (value instanceof RedisOperations) { super.setValue(((RedisOperations) value).opsForSet()); } else { - throw new java.lang.IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); + throw new IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); } } } diff --git a/src/main/java/org/springframework/data/redis/core/TimeToLiveAccessor.java b/src/main/java/org/springframework/data/redis/core/TimeToLiveAccessor.java index b8ea4091e..f5ffceac9 100644 --- a/src/main/java/org/springframework/data/redis/core/TimeToLiveAccessor.java +++ b/src/main/java/org/springframework/data/redis/core/TimeToLiveAccessor.java @@ -15,9 +15,11 @@ */ package org.springframework.data.redis.core; +import org.springframework.lang.Nullable; + /** * {@link TimeToLiveAccessor} extracts the objects time to live used for {@code EXPIRE}. - * + * * @author Christoph Strobl * @since 1.7 */ @@ -27,5 +29,6 @@ public interface TimeToLiveAccessor { * @param source must not be {@literal null}. * @return {@literal null} if not configured. */ + @Nullable Long getTimeToLive(Object source); } diff --git a/src/main/java/org/springframework/data/redis/core/ValueOperations.java b/src/main/java/org/springframework/data/redis/core/ValueOperations.java index c544e5219..98364e9fc 100644 --- a/src/main/java/org/springframework/data/redis/core/ValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ValueOperations.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2017 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 - * + * * http://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. @@ -20,9 +20,11 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.springframework.lang.Nullable; + /** * Redis operations for simple (or in Redis terminology 'string') values. - * + * * @author Costin Leau * @author Christoph Strobl * @author Mark Paluch @@ -54,8 +56,10 @@ public interface ValueOperations { * * @param key must not be {@literal null}. * @param value + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SETNX */ + @Nullable Boolean setIfAbsent(K key, V value); /** @@ -71,50 +75,62 @@ public interface ValueOperations { * not exist. * * @param map must not be {@literal null}. + * @param {@literal null} when used in pipeline / transaction. * @see Redis Documentation: MSET */ + @Nullable Boolean multiSetIfAbsent(Map map); /** * Get the value of {@code key}. * * @param key must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GET */ + @Nullable V get(Object key); /** * Set {@code value} of {@code key} and return its old value. - * + * * @param key must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GETSET */ + @Nullable V getAndSet(K key, V value); /** * Get multiple {@code keys}. Values are returned in the order of the requested keys. - * + * * @param keys must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: MGET */ + @Nullable List multiGet(Collection keys); /** * Increment an integer value stored as string value under {@code key} by {@code delta}. - * + * * @param key must not be {@literal null}. * @param delta + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: INCR */ + @Nullable Long increment(K key, long delta); /** * Increment a floating point number value stored as string value under {@code key} by {@code delta}. - * + * * @param key must not be {@literal null}. * @param delta + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: INCRBYFLOAT */ + @Nullable Double increment(K key, double delta); /** @@ -122,8 +138,10 @@ public interface ValueOperations { * * @param key must not be {@literal null}. * @param value + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: APPEND */ + @Nullable Integer append(K key, String value); /** @@ -132,8 +150,10 @@ public interface ValueOperations { * @param key must not be {@literal null}. * @param start * @param end + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GETRANGE */ + @Nullable String get(K key, long start, long end); /** @@ -150,8 +170,10 @@ public interface ValueOperations { * Get the length of the value stored at {@code key}. * * @param key must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: STRLEN */ + @Nullable Long size(K key); /** @@ -160,9 +182,11 @@ public interface ValueOperations { * @param key must not be {@literal null}. * @param offset * @param value + * @return {@literal null} when used in pipeline / transaction. * @since 1.5 * @see Redis Documentation: SETBIT */ + @Nullable Boolean setBit(K key, long offset, boolean value); /** @@ -170,9 +194,11 @@ public interface ValueOperations { * * @param key must not be {@literal null}. * @param offset + * @return {@literal null} when used in pipeline / transaction. * @since 1.5 * @see Redis Documentation: GETBIT */ + @Nullable Boolean getBit(K key, long offset); RedisOperations getOperations(); diff --git a/src/main/java/org/springframework/data/redis/core/ValueOperationsEditor.java b/src/main/java/org/springframework/data/redis/core/ValueOperationsEditor.java index 76f37c8f4..9ea2b2535 100644 --- a/src/main/java/org/springframework/data/redis/core/ValueOperationsEditor.java +++ b/src/main/java/org/springframework/data/redis/core/ValueOperationsEditor.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -19,7 +19,7 @@ import java.beans.PropertyEditorSupport; /** * PropertyEditor allowing for easy injection of {@link ValueOperations} from {@link RedisOperations}. - * + * * @author Costin Leau */ class ValueOperationsEditor extends PropertyEditorSupport { @@ -28,7 +28,7 @@ class ValueOperationsEditor extends PropertyEditorSupport { if (value instanceof RedisOperations) { super.setValue(((RedisOperations) value).opsForValue()); } else { - throw new java.lang.IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); + throw new IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); } } } diff --git a/src/main/java/org/springframework/data/redis/core/ZSetOperationsEditor.java b/src/main/java/org/springframework/data/redis/core/ZSetOperationsEditor.java index ef625559c..1be2d3c01 100644 --- a/src/main/java/org/springframework/data/redis/core/ZSetOperationsEditor.java +++ b/src/main/java/org/springframework/data/redis/core/ZSetOperationsEditor.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -19,7 +19,7 @@ import java.beans.PropertyEditorSupport; /** * PropertyEditor allowing for easy injection of {@link ZSetOperations} from {@link RedisOperations}. - * + * * @author Costin Leau */ class ZSetOperationsEditor extends PropertyEditorSupport { @@ -28,7 +28,7 @@ class ZSetOperationsEditor extends PropertyEditorSupport { if (value instanceof RedisOperations) { super.setValue(((RedisOperations) value).opsForZSet()); } else { - throw new java.lang.IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); + throw new IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class); } } } diff --git a/src/main/java/org/springframework/data/redis/core/convert/BinaryConverters.java b/src/main/java/org/springframework/data/redis/core/convert/BinaryConverters.java index 44c2b3000..8cdebfaab 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/BinaryConverters.java +++ b/src/main/java/org/springframework/data/redis/core/convert/BinaryConverters.java @@ -16,8 +16,10 @@ package org.springframework.data.redis.core.convert; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.ParseException; +import java.util.Arrays; import java.util.Date; import org.springframework.core.convert.converter.Converter; @@ -39,7 +41,7 @@ final class BinaryConverters { /** * Use {@literal UTF-8} as default charset. */ - public static final Charset CHARSET = Charset.forName("UTF-8"); + public static final Charset CHARSET = StandardCharsets.UTF_8; private BinaryConverters() {} @@ -265,7 +267,7 @@ final class BinaryConverters { // ignore } - throw new IllegalArgumentException("Cannot parse date out of " + source); + throw new IllegalArgumentException(String.format("Cannot parse date out of %s", Arrays.toString(source))); } } } diff --git a/src/main/java/org/springframework/data/redis/core/convert/Bucket.java b/src/main/java/org/springframework/data/redis/core/convert/Bucket.java index 171b696bd..d9f4c668e 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/Bucket.java +++ b/src/main/java/org/springframework/data/redis/core/convert/Bucket.java @@ -16,6 +16,7 @@ package org.springframework.data.redis.core.convert; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; @@ -42,7 +43,7 @@ public class Bucket { /** * Encoding used for converting {@link Byte} to and from {@link String}. */ - public static final Charset CHARSET = Charset.forName("UTF-8"); + public static final Charset CHARSET = StandardCharsets.UTF_8; private final Map data; @@ -72,12 +73,24 @@ public class Bucket { data.put(path, value); } + /** + * Remove the property at property dot {@code path}. + * + * @param path must not be {@literal null} or {@link String#isEmpty()}. + */ + public void remove(String path) { + + Assert.hasText(path, "Path to property must not be null or empty."); + data.remove(path); + } + /** * Get value assigned with path. * * @param path path must not be {@literal null} or {@link String#isEmpty()}. * @return {@literal null} if not set. */ + @Nullable public byte[] get(String path) { Assert.hasText(path, "Path to property must not be null or empty."); diff --git a/src/main/java/org/springframework/data/redis/core/convert/CompositeIndexResolver.java b/src/main/java/org/springframework/data/redis/core/convert/CompositeIndexResolver.java index 107811b8d..fe7aed0f0 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/CompositeIndexResolver.java +++ b/src/main/java/org/springframework/data/redis/core/convert/CompositeIndexResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2017 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. @@ -23,6 +23,7 @@ import java.util.List; import java.util.Set; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -59,7 +60,7 @@ public class CompositeIndexResolver implements IndexResolver { * @see org.springframework.data.redis.core.convert.IndexResolver#resolveIndexesFor(org.springframework.data.util.TypeInformation, java.lang.Object) */ @Override - public Set resolveIndexesFor(TypeInformation typeInformation, Object value) { + public Set resolveIndexesFor(TypeInformation typeInformation, @Nullable Object value) { if (resolvers.isEmpty()) { return Collections.emptySet(); @@ -77,7 +78,7 @@ public class CompositeIndexResolver implements IndexResolver { */ @Override public Set resolveIndexesFor(String keyspace, String path, TypeInformation typeInformation, - Object value) { + @Nullable Object value) { Set data = new LinkedHashSet<>(); for (IndexResolver resolver : resolvers) { diff --git a/src/main/java/org/springframework/data/redis/core/convert/IndexedDataFactoryProvider.java b/src/main/java/org/springframework/data/redis/core/convert/IndexedDataFactoryProvider.java index 252bf5549..dfe4ee641 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/IndexedDataFactoryProvider.java +++ b/src/main/java/org/springframework/data/redis/core/convert/IndexedDataFactoryProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2017 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. @@ -15,10 +15,13 @@ */ package org.springframework.data.redis.core.convert; +import lombok.RequiredArgsConstructor; + import org.springframework.data.geo.Point; import org.springframework.data.redis.core.index.GeoIndexDefinition; import org.springframework.data.redis.core.index.IndexDefinition; import org.springframework.data.redis.core.index.SimpleIndexDefinition; +import org.springframework.lang.Nullable; /** * @author Christoph Strobl @@ -30,6 +33,7 @@ class IndexedDataFactoryProvider { * @author Christoph Strobl * @since 1.8 */ + @Nullable IndexedDataFactory getIndexedDataFactory(IndexDefinition definition) { if (definition instanceof SimpleIndexDefinition) { @@ -48,14 +52,11 @@ class IndexedDataFactoryProvider { * @author Christoph Strobl * @since 1.8 */ + @RequiredArgsConstructor static class SimpleIndexedPropertyValueFactory implements IndexedDataFactory { final SimpleIndexDefinition indexDefinition; - public SimpleIndexedPropertyValueFactory(SimpleIndexDefinition indexDefinition) { - this.indexDefinition = indexDefinition; - } - public SimpleIndexedPropertyValue createIndexedDataFor(Object value) { return new SimpleIndexedPropertyValue(indexDefinition.getKeyspace(), indexDefinition.getIndexName(), @@ -67,14 +68,11 @@ class IndexedDataFactoryProvider { * @author Christoph Strobl * @since 1.8 */ + @RequiredArgsConstructor static class GeoIndexedPropertyValueFactory implements IndexedDataFactory { final GeoIndexDefinition indexDefinition; - public GeoIndexedPropertyValueFactory(GeoIndexDefinition indexDefinition) { - this.indexDefinition = indexDefinition; - } - public GeoIndexedPropertyValue createIndexedDataFor(Object value) { return new GeoIndexedPropertyValue(indexDefinition.getKeyspace(), indexDefinition.getPath(), diff --git a/src/main/java/org/springframework/data/redis/core/convert/KeyspaceConfiguration.java b/src/main/java/org/springframework/data/redis/core/convert/KeyspaceConfiguration.java index 040449dd7..e39b7f386 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/KeyspaceConfiguration.java +++ b/src/main/java/org/springframework/data/redis/core/convert/KeyspaceConfiguration.java @@ -21,7 +21,6 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.data.redis.core.RedisHash; import org.springframework.data.redis.core.TimeToLive; -import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -46,33 +45,6 @@ public class KeyspaceConfiguration { } } - @EnableRedisRepositories(keyspaceConfiguration = MyKeyspaceConfiguration.class) - static class MyConfig { - - } - - static class MyKeyspaceConfiguration extends KeyspaceConfiguration { - - @Override - protected Iterable initialConfiguration() { - return super.initialConfiguration(); - } - - @Override - public boolean hasSettingsFor(Class type) { - return true; - } - - @Override - public KeyspaceSettings getKeyspaceSettings(Class type) { - - KeyspaceSettings keyspaceSettings = new KeyspaceSettings(type, "my-keyspace"); - keyspaceSettings.setTimeToLive(3600L); - - return keyspaceSettings; - } - } - /** * Check if specific {@link KeyspaceSettings} are available for given type. * @@ -154,6 +126,7 @@ public class KeyspaceConfiguration { private final String keyspace; private final Class type; private final boolean inherit; + private @Nullable Long timeToLive; private @Nullable String timeToLivePropertyName; @@ -197,7 +170,6 @@ public class KeyspaceConfiguration { public String getTimeToLivePropertyName() { return timeToLivePropertyName; } - } /** @@ -211,7 +183,5 @@ public class KeyspaceConfiguration { public DefaultKeyspaceSetting(Class type) { super(type, "#default#", false); } - } - } 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 d01243700..adcdcf4f5 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 @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core.convert; +import lombok.RequiredArgsConstructor; + import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; @@ -61,6 +63,7 @@ import org.springframework.data.redis.core.mapping.RedisPersistentEntity; import org.springframework.data.redis.core.mapping.RedisPersistentProperty; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -124,8 +127,8 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { private final Comparator listKeyComparator = new NullSafeComparator<>(NaturalOrderingKeyComparator.INSTANCE, true); - private ReferenceResolver referenceResolver; private IndexResolver indexResolver; + private @Nullable ReferenceResolver referenceResolver; private CustomConversions customConversions; /** @@ -144,21 +147,18 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { * @param indexResolver can be {@literal null}. * @param referenceResolver must not be {@literal null}. */ - public MappingRedisConverter(RedisMappingContext mappingContext, IndexResolver indexResolver, - ReferenceResolver referenceResolver) { + public MappingRedisConverter(@Nullable RedisMappingContext mappingContext, @Nullable IndexResolver indexResolver, + @Nullable ReferenceResolver referenceResolver) { this.mappingContext = mappingContext != null ? mappingContext : new RedisMappingContext(); - entityInstantiators = new EntityInstantiators(); - + this.entityInstantiators = new EntityInstantiators(); this.conversionService = new DefaultConversionService(); this.customConversions = new RedisCustomConversions(); - - typeMapper = new DefaultTypeMapper<>(new RedisTypeAliasAccessor(this.conversionService)); - - this.referenceResolver = referenceResolver; + this.typeMapper = new DefaultTypeMapper<>(new RedisTypeAliasAccessor(this.conversionService)); this.indexResolver = indexResolver != null ? indexResolver : new PathIndexResolver(this.mappingContext); + this.referenceResolver = referenceResolver; } /* @@ -171,6 +171,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { } @SuppressWarnings("unchecked") + @Nullable private R readInternal(String path, Class type, RedisData source) { if (source.getBucket() == null || source.getBucket().isEmpty()) { @@ -404,7 +405,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { write(update.getValue(), sink); if (sink.getBucket().keySet().contains(TYPE_HINT_ALIAS)) { - sink.getBucket().put(TYPE_HINT_ALIAS, null); // overwrite stuff in here + sink.getBucket().remove(TYPE_HINT_ALIAS); // overwrite stuff in here } if (update.isRefreshTtl() && !update.getPropertyUpdates().isEmpty()) { @@ -515,6 +516,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { } } + @Nullable RedisPersistentProperty getTargetPropertyOrNullForPath(String path, Class type) { try { @@ -536,7 +538,8 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { * @param typeHint * @param sink */ - private void writeInternal(String keyspace, String path, Object value, TypeInformation typeHint, RedisData sink) { + private void writeInternal(String keyspace, String path, @Nullable Object value, TypeInformation typeHint, + RedisData sink) { if (value == null) { return; @@ -586,7 +589,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { } else if (persistentProperty.isCollectionLike()) { if (propertyValue == null) { - writeCollection(keyspace, propertyStringPath, (Iterable) null, + writeCollection(keyspace, propertyStringPath, null, persistentProperty.getTypeInformation().getRequiredComponentType(), sink); } else { @@ -677,7 +680,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { * @param typeHint * @param sink */ - private void writeCollection(String keyspace, String path, Iterable values, TypeInformation typeHint, + private void writeCollection(String keyspace, String path, @Nullable Iterable values, TypeInformation typeHint, RedisData sink) { if (values == null) { @@ -707,7 +710,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { } } - private void writeToBucket(String path, Object value, RedisData sink, Class propertyType) { + private void writeToBucket(String path, @Nullable Object value, RedisData sink, Class propertyType) { if (value == null || (value instanceof Optional && !((Optional) value).isPresent())) { return; @@ -743,7 +746,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { private Object readCollectionOrArray(String path, Class collectionType, Class valueType, Bucket bucket) { List keys = new ArrayList<>(bucket.extractAllKeysFor(path)); - Collections.sort(keys, listKeyComparator); + keys.sort(listKeyComparator); boolean isArray = collectionType.isArray(); Class collectionTypeToUse = isArray ? ArrayList.class : collectionType; @@ -815,6 +818,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { * @param source * @return */ + @Nullable private Map readMapOfSimpleTypes(String path, Class mapType, Class keyType, Class valueType, RedisData source) { @@ -853,6 +857,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { * @param source * @return */ + @Nullable private Map readMapOfComplexTypes(String path, Class mapType, Class keyType, Class valueType, RedisData source) { @@ -897,9 +902,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { String typeName = fromBytes(typeInfo, String.class); try { return ClassUtils.forName(typeName, this.getClass().getClassLoader()); - } catch (ClassNotFoundException e) { - throw new MappingException(String.format("Cannot find class for type %s. ", typeName), e); - } catch (LinkageError e) { + } catch (ClassNotFoundException | LinkageError e) { throw new MappingException(String.format("Cannot find class for type %s. ", typeName), e); } } @@ -940,6 +943,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { * @param valueType to be used for conversion before setting the actual value. * @return */ + @Nullable private Object toArray(Collection source, Class arrayType, Class valueType) { if (source.isEmpty()) { @@ -960,21 +964,21 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { return i > 0 ? targetArray : null; } - /** - * Set {@link CustomConversions} to be applied. - * - * @param customConversions - */ - public void setCustomConversions(CustomConversions customConversions) { - this.customConversions = customConversions != null ? customConversions : new RedisCustomConversions(); + public void setIndexResolver(IndexResolver indexResolver) { + this.indexResolver = indexResolver; } public void setReferenceResolver(ReferenceResolver referenceResolver) { this.referenceResolver = referenceResolver; } - public void setIndexResolver(IndexResolver indexResolver) { - this.indexResolver = indexResolver; + /** + * Set {@link CustomConversions} to be applied. + * + * @param customConversions + */ + public void setCustomConversions(@Nullable CustomConversions customConversions) { + this.customConversions = customConversions != null ? customConversions : new RedisCustomConversions(); } /* @@ -1007,19 +1011,13 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { /** * @author Christoph Strobl */ + @RequiredArgsConstructor private static class ConverterAwareParameterValueProvider implements PropertyValueProvider { private final String path; private final RedisData source; private final ConversionService conversionService; - public ConverterAwareParameterValueProvider(String path, RedisData source, ConversionService conversionService) { - - this.path = path; - this.source = source; - this.conversionService = conversionService; - } - @Override @SuppressWarnings("unchecked") public T getPropertyValue(RedisPersistentProperty property) { @@ -1129,7 +1127,7 @@ public class MappingRedisConverter implements RedisConverter, InitializingBean { private static class Part implements Comparable { private final String rawValue; - private final Long longValue; + private final @Nullable Long longValue; Part(String value, boolean isDigit) { diff --git a/src/main/java/org/springframework/data/redis/core/convert/PathIndexResolver.java b/src/main/java/org/springframework/data/redis/core/convert/PathIndexResolver.java index f7627833b..a9c397ab7 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/PathIndexResolver.java +++ b/src/main/java/org/springframework/data/redis/core/convert/PathIndexResolver.java @@ -41,6 +41,7 @@ import org.springframework.data.redis.core.mapping.RedisPersistentEntity; import org.springframework.data.redis.core.mapping.RedisPersistentProperty; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -57,9 +58,9 @@ public class PathIndexResolver implements IndexResolver { private final Set> VALUE_TYPES = new HashSet<>(Arrays.> asList(Point.class, GeoLocation.class)); - private ConfigurableIndexDefinitionProvider indexConfiguration; - private RedisMappingContext mappingContext; - private IndexedDataFactoryProvider indexedDataFactoryProvider; + private final ConfigurableIndexDefinitionProvider indexConfiguration; + private final RedisMappingContext mappingContext; + private final IndexedDataFactoryProvider indexedDataFactoryProvider; /** * Creates new {@link PathIndexResolver} with empty {@link IndexConfiguration}. @@ -76,6 +77,7 @@ public class PathIndexResolver implements IndexResolver { public PathIndexResolver(RedisMappingContext mappingContext) { Assert.notNull(mappingContext, "MappingContext must not be null!"); + this.mappingContext = mappingContext; this.indexConfiguration = mappingContext.getMappingConfiguration().getIndexConfiguration(); this.indexedDataFactoryProvider = new IndexedDataFactoryProvider(); @@ -85,7 +87,7 @@ public class PathIndexResolver implements IndexResolver { * (non-Javadoc) * @see org.springframework.data.redis.core.convert.IndexResolver#resolveIndexesFor(org.springframework.data.util.TypeInformation, java.lang.Object) */ - public Set resolveIndexesFor(TypeInformation typeInformation, Object value) { + public Set resolveIndexesFor(TypeInformation typeInformation, @Nullable Object value) { return doResolveIndexesFor(mappingContext.getRequiredPersistentEntity(typeInformation).getKeySpace(), "", typeInformation, null, value); } @@ -100,7 +102,7 @@ public class PathIndexResolver implements IndexResolver { } private Set doResolveIndexesFor(final String keyspace, final String path, - TypeInformation typeInformation, PersistentProperty fallback, Object value) { + TypeInformation typeInformation, @Nullable PersistentProperty fallback, @Nullable Object value) { RedisPersistentEntity entity = mappingContext.getPersistentEntity(typeInformation); @@ -196,8 +198,8 @@ public class PathIndexResolver implements IndexResolver { return indexes; } - protected Set resolveIndex(String keyspace, String propertyPath, PersistentProperty property, - Object value) { + protected Set resolveIndex(String keyspace, String propertyPath, + @Nullable PersistentProperty property, @Nullable Object value) { String path = normalizeIndexPath(propertyPath, property); @@ -257,7 +259,7 @@ public class PathIndexResolver implements IndexResolver { return true; } - private String normalizeIndexPath(String path, PersistentProperty property) { + private String normalizeIndexPath(String path, @Nullable PersistentProperty property) { if (property == null) { return path; diff --git a/src/main/java/org/springframework/data/redis/core/convert/RedisData.java b/src/main/java/org/springframework/data/redis/core/convert/RedisData.java index c994d68f3..8241f27df 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/RedisData.java +++ b/src/main/java/org/springframework/data/redis/core/convert/RedisData.java @@ -30,23 +30,23 @@ import org.springframework.util.Assert; * points to additional structures holding the objects is for searching. * * @author Christoph Strobl + * @author Mark Paluch * @since 1.7 */ public class RedisData { + private final Bucket bucket; + private final Set indexedData; + private @Nullable String keyspace; private @Nullable String id; - - private Bucket bucket; - private Set indexedData; - private @Nullable Long timeToLive; /** * Creates new {@link RedisData} with empty {@link Bucket}. */ public RedisData() { - this(Collections. emptyMap()); + this(Collections.emptyMap()); } /** @@ -66,6 +66,7 @@ public class RedisData { public RedisData(Bucket bucket) { Assert.notNull(bucket, "Bucket must not be null!"); + this.bucket = bucket; this.indexedData = new HashSet<>(); } diff --git a/src/main/java/org/springframework/data/redis/core/convert/ReferenceResolver.java b/src/main/java/org/springframework/data/redis/core/convert/ReferenceResolver.java index cd6eccb12..c0fa2a423 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/ReferenceResolver.java +++ b/src/main/java/org/springframework/data/redis/core/convert/ReferenceResolver.java @@ -18,6 +18,7 @@ package org.springframework.data.redis.core.convert; import java.util.Map; import org.springframework.data.annotation.Reference; +import org.springframework.lang.Nullable; /** * {@link ReferenceResolver} retrieves Objects marked with {@link Reference} from Redis. @@ -33,5 +34,6 @@ public interface ReferenceResolver { * @param keyspace must not be {@literal null}. * @return {@literal null} if referenced object does not exist. */ + @Nullable Map resolveReference(Object id, String keyspace); } diff --git a/src/main/java/org/springframework/data/redis/core/convert/ReferenceResolverImpl.java b/src/main/java/org/springframework/data/redis/core/convert/ReferenceResolverImpl.java index 2e03427b0..f1561e4bf 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/ReferenceResolverImpl.java +++ b/src/main/java/org/springframework/data/redis/core/convert/ReferenceResolverImpl.java @@ -21,6 +21,7 @@ import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisKeyValueAdapter; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.convert.BinaryConverters.StringToBytesConverter; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -51,6 +52,7 @@ public class ReferenceResolverImpl implements ReferenceResolver { * @see org.springframework.data.redis.core.convert.ReferenceResolver#resolveReference(java.lang.Object, java.lang.String) */ @Override + @Nullable public Map resolveReference(Object id, String keyspace) { byte[] key = converter.convert(keyspace + ":" + id); diff --git a/src/main/java/org/springframework/data/redis/core/convert/SimpleIndexedPropertyValue.java b/src/main/java/org/springframework/data/redis/core/convert/SimpleIndexedPropertyValue.java index 0c936c1cc..f07146ba4 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/SimpleIndexedPropertyValue.java +++ b/src/main/java/org/springframework/data/redis/core/convert/SimpleIndexedPropertyValue.java @@ -15,7 +15,8 @@ */ package org.springframework.data.redis.core.convert; -import org.springframework.util.ObjectUtils; +import lombok.EqualsAndHashCode; +import lombok.ToString; /** * {@link IndexedData} implementation indicating storage of data within a Redis Set. @@ -24,6 +25,8 @@ import org.springframework.util.ObjectUtils; * @author Rob Winch * @since 1.7 */ +@EqualsAndHashCode +@ToString public class SimpleIndexedPropertyValue implements IndexedData { private final String keyspace; @@ -70,55 +73,4 @@ public class SimpleIndexedPropertyValue implements IndexedData { public String getKeyspace() { return this.keyspace; } - - /* - * (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - - int result = 1; - result += ObjectUtils.nullSafeHashCode(keyspace); - result += ObjectUtils.nullSafeHashCode(indexName); - result += ObjectUtils.nullSafeHashCode(value); - return result; - } - - /* - * (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof SimpleIndexedPropertyValue)) { - return false; - } - - SimpleIndexedPropertyValue that = (SimpleIndexedPropertyValue) obj; - - if (!ObjectUtils.nullSafeEquals(this.keyspace, that.keyspace)) { - return false; - } - if (!ObjectUtils.nullSafeEquals(this.indexName, that.indexName)) { - return false; - } - return ObjectUtils.nullSafeEquals(this.value, that.value); - } - - /* - * (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return "SimpleIndexedPropertyValue [keyspace=" + keyspace + ", indexName=" + indexName + ", value=" + value + "]"; - } - } diff --git a/src/main/java/org/springframework/data/redis/core/convert/SpelIndexResolver.java b/src/main/java/org/springframework/data/redis/core/convert/SpelIndexResolver.java index 0fe113461..d131988d5 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/SpelIndexResolver.java +++ b/src/main/java/org/springframework/data/redis/core/convert/SpelIndexResolver.java @@ -50,7 +50,7 @@ public class SpelIndexResolver implements IndexResolver { private @Nullable BeanResolver beanResolver; - private Map expressionCache; + private final Map expressionCache; /** * Creates a new instance using a default {@link SpelExpressionParser}. diff --git a/src/main/java/org/springframework/data/redis/core/convert/package-info.java b/src/main/java/org/springframework/data/redis/core/convert/package-info.java index d064994da..bd40f0478 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/package-info.java +++ b/src/main/java/org/springframework/data/redis/core/convert/package-info.java @@ -2,4 +2,5 @@ * Converters for Redis repository support utilizing mapping metadata. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.core.convert; diff --git a/src/main/java/org/springframework/data/redis/core/index/GeoIndexDefinition.java b/src/main/java/org/springframework/data/redis/core/index/GeoIndexDefinition.java index 04d149db0..a6ec2ce28 100644 --- a/src/main/java/org/springframework/data/redis/core/index/GeoIndexDefinition.java +++ b/src/main/java/org/springframework/data/redis/core/index/GeoIndexDefinition.java @@ -17,6 +17,7 @@ package org.springframework.data.redis.core.index; import org.springframework.data.geo.Point; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; +import org.springframework.lang.Nullable; /** * @author Christoph Strobl @@ -54,7 +55,7 @@ public class GeoIndexDefinition extends RedisIndexDefinition implements PathBase static class PointValueTransformer implements IndexValueTransformer { @Override - public Point convert(Object source) { + public Point convert(@Nullable Object source) { if (source == null || source instanceof Point) { return (Point) source; diff --git a/src/main/java/org/springframework/data/redis/core/index/IndexDefinition.java b/src/main/java/org/springframework/data/redis/core/index/IndexDefinition.java index a80587a8f..76bc1344a 100644 --- a/src/main/java/org/springframework/data/redis/core/index/IndexDefinition.java +++ b/src/main/java/org/springframework/data/redis/core/index/IndexDefinition.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.core.index; +import lombok.Value; + import java.util.Collection; import org.springframework.data.util.TypeInformation; @@ -24,8 +26,9 @@ import org.springframework.data.util.TypeInformation; * conditions allows to define {@link Condition} that have to be passed in order to add a value to the index. This * allows to fine grained tune the index structure. {@link IndexValueTransformer} gets applied to the raw value for * creating the actual index entry. - * + * * @author Christoph Strobl + * @author Mark Paluch * @since 1.7 */ public interface IndexDefinition { @@ -55,40 +58,21 @@ public interface IndexDefinition { * @since 1.7 * @param */ - public static interface Condition { + interface Condition { boolean matches(T value, IndexingContext context); } /** * Context in which a particular value is about to get indexed. - * + * * @author Christoph Strobl * @since 1.7 */ + @Value public class IndexingContext { private final String keyspace; private final String path; private final TypeInformation typeInformation; - - public IndexingContext(String keyspace, String path, TypeInformation typeInformation) { - - this.keyspace = keyspace; - this.path = path; - this.typeInformation = typeInformation; - } - - public String getKeyspace() { - return keyspace; - } - - public String getPath() { - return path; - } - - public TypeInformation getTypeInformation() { - return typeInformation; - } } - } diff --git a/src/main/java/org/springframework/data/redis/core/index/IndexDefinitionProvider.java b/src/main/java/org/springframework/data/redis/core/index/IndexDefinitionProvider.java index 366386beb..fc8b23e4d 100644 --- a/src/main/java/org/springframework/data/redis/core/index/IndexDefinitionProvider.java +++ b/src/main/java/org/springframework/data/redis/core/index/IndexDefinitionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2017 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. @@ -20,14 +20,14 @@ import java.util.Set; /** * {@link IndexDefinitionProvider} give access to {@link IndexDefinition}s for creating secondary index structures. - * + * * @author Christoph Strobl * @since 1.7 */ public interface IndexDefinitionProvider { /** - * Gets all of the {@link RedisIndexSetting} for a given keyspace. + * Checks if an index is defined for a given {@code keyspace}. * * @param keyspace the keyspace to get * @return never {@literal null} @@ -35,7 +35,7 @@ public interface IndexDefinitionProvider { boolean hasIndexFor(Serializable keyspace); /** - * Checks if an index is defined for a given keyspace and property path. + * Checks if an index is defined for a given {@code keyspace} and property {@code path}. * * @param keyspace * @param path @@ -44,7 +44,7 @@ public interface IndexDefinitionProvider { boolean hasIndexFor(Serializable keyspace, String path); /** - * Get the list of {@link IndexDefinition} for a given keyspace. + * Get the list of {@link IndexDefinition} for a given {@code keyspace}. * * @param keyspace * @return never {@literal null}. @@ -52,7 +52,7 @@ public interface IndexDefinitionProvider { Set getIndexDefinitionsFor(Serializable keyspace); /** - * Get the list of {@link IndexDefinition} for a given keyspace and property path. + * Get the list of {@link IndexDefinition} for a given {@code keyspace} and property {@code path}. * * @param keyspace * @param path diff --git a/src/main/java/org/springframework/data/redis/core/index/PathBasedRedisIndexDefinition.java b/src/main/java/org/springframework/data/redis/core/index/PathBasedRedisIndexDefinition.java index 1411a9e34..478da7a00 100644 --- a/src/main/java/org/springframework/data/redis/core/index/PathBasedRedisIndexDefinition.java +++ b/src/main/java/org/springframework/data/redis/core/index/PathBasedRedisIndexDefinition.java @@ -15,9 +15,11 @@ */ package org.springframework.data.redis.core.index; +import org.springframework.lang.Nullable; + /** * {@link IndexDefinition} that is based on a property paths. - * + * * @author Christoph Strobl * @since 1.7 */ @@ -26,6 +28,7 @@ public interface PathBasedRedisIndexDefinition extends IndexDefinition { /** * @return can be {@literal null}. */ + @Nullable String getPath(); } diff --git a/src/main/java/org/springframework/data/redis/core/index/RedisIndexDefinition.java b/src/main/java/org/springframework/data/redis/core/index/RedisIndexDefinition.java index 0d6f25082..4160bb20a 100644 --- a/src/main/java/org/springframework/data/redis/core/index/RedisIndexDefinition.java +++ b/src/main/java/org/springframework/data/redis/core/index/RedisIndexDefinition.java @@ -35,8 +35,9 @@ public abstract class RedisIndexDefinition implements IndexDefinition { private final String keyspace; private final String indexName; - private final String path; - private List> conditions; + private final @Nullable String path; + private final List> conditions; + private @Nullable IndexValueTransformer valueTransformer; /** @@ -46,7 +47,7 @@ public abstract class RedisIndexDefinition implements IndexDefinition { * @param path * @param indexName */ - protected RedisIndexDefinition(String keyspace, String path, String indexName) { + protected RedisIndexDefinition(String keyspace, @Nullable String path, String indexName) { this.keyspace = keyspace; this.indexName = indexName; @@ -90,6 +91,7 @@ public abstract class RedisIndexDefinition implements IndexDefinition { return indexName; } + @Nullable public String getPath() { return this.path; } diff --git a/src/main/java/org/springframework/data/redis/core/index/SpelIndexDefinition.java b/src/main/java/org/springframework/data/redis/core/index/SpelIndexDefinition.java index 8eaadeff6..59ad352f9 100644 --- a/src/main/java/org/springframework/data/redis/core/index/SpelIndexDefinition.java +++ b/src/main/java/org/springframework/data/redis/core/index/SpelIndexDefinition.java @@ -15,70 +15,44 @@ */ package org.springframework.data.redis.core.index; +import lombok.EqualsAndHashCode; + import org.springframework.data.redis.core.convert.SpelIndexResolver; import org.springframework.expression.spel.standard.SpelExpression; -import org.springframework.util.ObjectUtils; /** * {@link SpelIndexDefinition} defines index that is evaluated based on a {@link SpelExpression} requires the * {@link SpelIndexResolver} to be evaluated. - * + * * @author Christoph Strobl * @since 1.7 */ +@EqualsAndHashCode(callSuper = true) public class SpelIndexDefinition extends RedisIndexDefinition { private final String expression; /** * Creates new {@link SpelIndexDefinition}. - * + * * @param keyspace must not be {@literal null}. * @param expression must not be {@literal null}. * @param indexName must not be {@literal null}. */ public SpelIndexDefinition(String keyspace, String expression, String indexName) { + super(keyspace, null, indexName); + this.expression = expression; } /** * Get the raw expression. - * + * * @return */ public String getExpression() { return expression; } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.core.index.RedisIndexDefinition#hashCode() - */ - @Override - public int hashCode() { - int result = super.hashCode(); - result += ObjectUtils.nullSafeHashCode(expression); - return result; - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.core.index.RedisIndexDefinition#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!super.equals(obj)) { - return false; - } - if (!(obj instanceof SpelIndexDefinition)) { - return false; - } - SpelIndexDefinition that = (SpelIndexDefinition) obj; - return ObjectUtils.nullSafeEquals(this.expression, that.expression); - } - } diff --git a/src/main/java/org/springframework/data/redis/core/index/package-info.java b/src/main/java/org/springframework/data/redis/core/index/package-info.java index 3c348dc53..3bd601ffe 100644 --- a/src/main/java/org/springframework/data/redis/core/index/package-info.java +++ b/src/main/java/org/springframework/data/redis/core/index/package-info.java @@ -2,4 +2,5 @@ * Abstractions for Redis secondary indexes. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.core.index; diff --git a/src/main/java/org/springframework/data/redis/core/mapping/BasicRedisPersistentEntity.java b/src/main/java/org/springframework/data/redis/core/mapping/BasicRedisPersistentEntity.java index 42d4e2855..fb8a0723a 100644 --- a/src/main/java/org/springframework/data/redis/core/mapping/BasicRedisPersistentEntity.java +++ b/src/main/java/org/springframework/data/redis/core/mapping/BasicRedisPersistentEntity.java @@ -35,7 +35,7 @@ import org.springframework.util.Assert; public class BasicRedisPersistentEntity extends BasicKeyValuePersistentEntity implements RedisPersistentEntity { - private TimeToLiveAccessor timeToLiveAccessor; + private final TimeToLiveAccessor timeToLiveAccessor; /** * Creates new {@link BasicRedisPersistentEntity}. @@ -44,7 +44,7 @@ public class BasicRedisPersistentEntity extends BasicKeyValuePersistentEntity * @param fallbackKeySpaceResolver can be {@literal null}. * @param timeToLiveAccessor can be {@literal null}. */ - public BasicRedisPersistentEntity(TypeInformation information, KeySpaceResolver fallbackKeySpaceResolver, + public BasicRedisPersistentEntity(TypeInformation information, @Nullable KeySpaceResolver fallbackKeySpaceResolver, TimeToLiveAccessor timeToLiveAccessor) { super(information, fallbackKeySpaceResolver); diff --git a/src/main/java/org/springframework/data/redis/core/mapping/RedisMappingContext.java b/src/main/java/org/springframework/data/redis/core/mapping/RedisMappingContext.java index 2f0a28ab4..8f2a8ecca 100644 --- a/src/main/java/org/springframework/data/redis/core/mapping/RedisMappingContext.java +++ b/src/main/java/org/springframework/data/redis/core/mapping/RedisMappingContext.java @@ -76,7 +76,7 @@ public class RedisMappingContext extends KeyValueMappingContext implements SortCriterion { } public SortQuery build() { - return new DefaultSortQuery<>(key, by, limit, order, alpha, getKeys); + return new DefaultSortQuery<>(key, order, alpha, limit, by, getKeys); } public SortCriterion limit(long offset, long count) { diff --git a/src/main/java/org/springframework/data/redis/core/query/DefaultSortQuery.java b/src/main/java/org/springframework/data/redis/core/query/DefaultSortQuery.java index ad77f1530..96e41109e 100644 --- a/src/main/java/org/springframework/data/redis/core/query/DefaultSortQuery.java +++ b/src/main/java/org/springframework/data/redis/core/query/DefaultSortQuery.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -15,61 +15,38 @@ */ package org.springframework.data.redis.core.query; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + import java.util.List; import org.springframework.data.redis.connection.SortParameters.Order; import org.springframework.data.redis.connection.SortParameters.Range; +import org.springframework.lang.Nullable; /** * Default SortQuery implementation. - * + * * @author Costin Leau + * @author Mark Paluch */ +@Getter +@RequiredArgsConstructor class DefaultSortQuery implements SortQuery { private final K key; - private final Boolean alpha; - private final Order order; - private final Range limit; - private final String by; - private final List gets; - - DefaultSortQuery(K key, String by, Range limit, Order order, Boolean alpha, List gets) { - this.key = key; - this.by = by; - this.limit = limit; - this.order = order; - this.alpha = alpha; - this.gets = gets; - } - - public String getBy() { - return by; - } - - public Range getLimit() { - return limit; - } - - public Order getOrder() { - return order; - } + private final @Nullable Order order; + private final @Nullable Boolean alpha; + private final @Nullable Range limit; + private final @Nullable String by; + private final List getPattern; public Boolean isAlphabetic() { return alpha; } - public K getKey() { - return key; - } - - public List getGetPattern() { - return gets; - } - public String toString() { - return "DefaultSortQuery [alpha=" + alpha + ", by=" + by + ", gets=" + gets + ", key=" + key + ", limit=" + limit - + ", order=" + order + "]"; + return "DefaultSortQuery [alpha=" + alpha + ", by=" + by + ", gets=" + getPattern + ", key=" + key + ", limit=" + + limit + ", order=" + order + "]"; } - } diff --git a/src/main/java/org/springframework/data/redis/core/query/SortQuery.java b/src/main/java/org/springframework/data/redis/core/query/SortQuery.java index 3a4aa88fd..cb88983ec 100644 --- a/src/main/java/org/springframework/data/redis/core/query/SortQuery.java +++ b/src/main/java/org/springframework/data/redis/core/query/SortQuery.java @@ -1,12 +1,12 @@ /* - * Copyright 2011-2013 the original author or authors. - * + * Copyright 2011-2017 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 - * + * * http://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. @@ -22,54 +22,60 @@ 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.core.RedisTemplate; +import org.springframework.lang.Nullable; /** * High-level abstraction over a Redis SORT (generified equivalent of {@link SortParameters}). To be used with * {@link RedisTemplate} (just as {@link SortParameters} is used by {@link RedisConnection}). - * + * * @author Costin Leau + * @author Mark Paluch */ public interface SortQuery { - /** - * Returns the sorting order. Can be null if nothing is specified. - * - * @return sorting order - */ - Order getOrder(); - - /** - * Indicates if the sorting is numeric (default) or alphabetical (lexicographical). Can be null if nothing is - * specified. - * - * @return the type of sorting - */ - Boolean isAlphabetic(); - - /** - * Returns the sorting limit (range or pagination). Can be null if nothing is specified. - * - * @return sorting limit/range - */ - Range getLimit(); - /** * Return the target key for sorting. - * + * * @return the target key */ K getKey(); + /** + * Returns the sorting order. Can be null if nothing is specified. + * + * @return sorting order + */ + @Nullable + Order getOrder(); + + /** + * Indicates if the sorting is numeric (default) or alphabetical (lexicographical). Can be null if nothing is + * specified. + * + * @return the type of sorting + */ + @Nullable + Boolean isAlphabetic(); + + /** + * Returns the sorting limit (range or pagination). Can be null if nothing is specified. + * + * @return sorting limit/range + */ + @Nullable + Range getLimit(); + /** * Returns the pattern of the external key used for sorting. - * + * * @return the external key pattern */ + @Nullable String getBy(); /** * Returns the external key(s) whose values are returned by the sort. - * + * * @return the (list of) keys used for GET */ List getGetPattern(); diff --git a/src/main/java/org/springframework/data/redis/core/query/package-info.java b/src/main/java/org/springframework/data/redis/core/query/package-info.java index ab0db10ef..73208952a 100644 --- a/src/main/java/org/springframework/data/redis/core/query/package-info.java +++ b/src/main/java/org/springframework/data/redis/core/query/package-info.java @@ -2,5 +2,6 @@ * Query package for Redis template. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.core.query; diff --git a/src/main/java/org/springframework/data/redis/core/script/DefaultReactiveScriptExecutor.java b/src/main/java/org/springframework/data/redis/core/script/DefaultReactiveScriptExecutor.java index f1aab5965..823caacc9 100644 --- a/src/main/java/org/springframework/data/redis/core/script/DefaultReactiveScriptExecutor.java +++ b/src/main/java/org/springframework/data/redis/core/script/DefaultReactiveScriptExecutor.java @@ -124,6 +124,7 @@ public class DefaultReactiveScriptExecutor implements ReactiveScriptExecutor< return script.returnsRawValue() ? result : deserializeResult(resultReader, result); } + @SuppressWarnings("Convert2MethodRef") protected ByteBuffer[] keysAndArgs(RedisElementWriter argsWriter, List keys, List args) { return Stream.concat(keys.stream().map(t -> keySerializer().getWriter().write(t)), diff --git a/src/main/java/org/springframework/data/redis/core/script/DefaultRedisScript.java b/src/main/java/org/springframework/data/redis/core/script/DefaultRedisScript.java index 894891bae..03e7a757d 100644 --- a/src/main/java/org/springframework/data/redis/core/script/DefaultRedisScript.java +++ b/src/main/java/org/springframework/data/redis/core/script/DefaultRedisScript.java @@ -29,7 +29,7 @@ import org.springframework.util.Assert; * Default implementation of {@link RedisScript}. Delegates to an underlying {@link ScriptSource} to retrieve script * text and detect if script has been modified (and thus should have SHA1 re-calculated). This class is best used as a * Singleton to avoid re-calculation of SHA1 on every script execution. - * + * * @author Jennifer Hickey * @author Christoph Strobl * @param The script result type. Should be one of Long, Boolean, List, or deserialized value type. Can be null if @@ -37,16 +37,16 @@ import org.springframework.util.Assert; */ public class DefaultRedisScript implements RedisScript, InitializingBean { + private final Object shaModifiedMonitor = new Object(); + private @Nullable ScriptSource scriptSource; private @Nullable String sha1; private @Nullable Class resultType; - private final Object shaModifiedMonitor = new Object(); /** * Creates a new {@link DefaultRedisScript} */ public DefaultRedisScript() { - } /** @@ -61,11 +61,11 @@ public class DefaultRedisScript implements RedisScript, InitializingBean { /** * Creates a new {@link DefaultRedisScript} - * + * * @param script must not be {@literal null}. * @param resultType can be {@literal null}. */ - public DefaultRedisScript(String script, Class resultType) { + public DefaultRedisScript(String script, @Nullable Class resultType) { this.setScriptText(script); this.resultType = resultType; diff --git a/src/main/java/org/springframework/data/redis/core/script/DefaultScriptExecutor.java b/src/main/java/org/springframework/data/redis/core/script/DefaultScriptExecutor.java index 7ee7a76a7..52eae6d45 100644 --- a/src/main/java/org/springframework/data/redis/core/script/DefaultScriptExecutor.java +++ b/src/main/java/org/springframework/data/redis/core/script/DefaultScriptExecutor.java @@ -37,7 +37,7 @@ import org.springframework.data.redis.serializer.RedisSerializer; */ public class DefaultScriptExecutor implements ScriptExecutor { - private RedisTemplate template; + private final RedisTemplate template; /** * @param template The {@link RedisTemplate} to use diff --git a/src/main/java/org/springframework/data/redis/core/script/ScriptUtils.java b/src/main/java/org/springframework/data/redis/core/script/ScriptUtils.java index b98673beb..6fa6d8d62 100644 --- a/src/main/java/org/springframework/data/redis/core/script/ScriptUtils.java +++ b/src/main/java/org/springframework/data/redis/core/script/ScriptUtils.java @@ -65,7 +65,7 @@ class ScriptUtils { /** * Deserialize {@code result} using {@link RedisElementReader} to the reader type. Collection types and intermediate - * collection elements are deserialized recursivly. + * collection elements are deserialized recursively. * * @param reader must not be {@literal null}. * @param result must not be {@literal null}. @@ -75,7 +75,6 @@ class ScriptUtils { static T deserializeResult(RedisElementReader reader, Object result) { if (result instanceof ByteBuffer) { - return reader.read((ByteBuffer) result); } diff --git a/src/main/java/org/springframework/data/redis/core/script/ScriptingException.java b/src/main/java/org/springframework/data/redis/core/script/ScriptingException.java index d6234949e..6f6471a5c 100644 --- a/src/main/java/org/springframework/data/redis/core/script/ScriptingException.java +++ b/src/main/java/org/springframework/data/redis/core/script/ScriptingException.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2017 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. @@ -19,28 +19,29 @@ import org.springframework.core.NestedRuntimeException; /** * {@link RuntimeException} thrown when issues occur with {@link RedisScript}s - * + * * @author Jennifer Hickey + * @author Mark Paluch */ @SuppressWarnings("serial") public class ScriptingException extends NestedRuntimeException { /** - * Constructs a new ScriptingException instance. - * - * @param msg - * @param cause - */ - public ScriptingException(String msg, Throwable cause) { - super(msg, cause); - } - - /** - * Constructs a new ScriptingException instance. - * - * @param msg + * Constructs a new {@link ScriptingException} instance. + * + * @param msg the detail message. */ public ScriptingException(String msg) { super(msg); } + + /** + * Constructs a new {@link ScriptingException} instance. + * + * @param msg the detail message. + * @param cause the nested exception. + */ + public ScriptingException(String msg, Throwable cause) { + super(msg, cause); + } } diff --git a/src/main/java/org/springframework/data/redis/core/script/package-info.java b/src/main/java/org/springframework/data/redis/core/script/package-info.java index ae6deb18f..0e50ced96 100644 --- a/src/main/java/org/springframework/data/redis/core/script/package-info.java +++ b/src/main/java/org/springframework/data/redis/core/script/package-info.java @@ -2,4 +2,5 @@ * Lua script execution abstraction. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.core.script; diff --git a/src/main/java/org/springframework/data/redis/core/types/Expiration.java b/src/main/java/org/springframework/data/redis/core/types/Expiration.java index 69e748b85..df2297ab7 100644 --- a/src/main/java/org/springframework/data/redis/core/types/Expiration.java +++ b/src/main/java/org/springframework/data/redis/core/types/Expiration.java @@ -18,6 +18,7 @@ package org.springframework.data.redis.core.types; import java.time.Duration; import java.util.concurrent.TimeUnit; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -39,7 +40,7 @@ public class Expiration { * @param expirationTime can be {@literal null}. Defaulted to {@link TimeUnit#SECONDS} * @param timeUnit */ - protected Expiration(long expirationTime, TimeUnit timeUnit) { + protected Expiration(long expirationTime, @Nullable TimeUnit timeUnit) { this.expirationTime = expirationTime; this.timeUnit = timeUnit != null ? timeUnit : TimeUnit.SECONDS; @@ -124,7 +125,7 @@ public class Expiration { * @param timeUnit can be {@literal null}. Defaulted to {@link TimeUnit#SECONDS} * @return */ - public static Expiration from(long expirationTime, TimeUnit timeUnit) { + public static Expiration from(long expirationTime, @Nullable TimeUnit timeUnit) { if (ObjectUtils.nullSafeEquals(timeUnit, TimeUnit.MICROSECONDS) || ObjectUtils.nullSafeEquals(timeUnit, TimeUnit.NANOSECONDS) diff --git a/src/main/java/org/springframework/data/redis/core/types/RedisClientInfo.java b/src/main/java/org/springframework/data/redis/core/types/RedisClientInfo.java index 583072d9c..e456365c0 100644 --- a/src/main/java/org/springframework/data/redis/core/types/RedisClientInfo.java +++ b/src/main/java/org/springframework/data/redis/core/types/RedisClientInfo.java @@ -15,27 +15,33 @@ */ package org.springframework.data.redis.core.types; +import lombok.EqualsAndHashCode; + import java.io.IOException; import java.io.StringReader; import java.util.Properties; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** * {@link RedisClientInfo} provides general and statistical information about client connections. - * + * * @author Christoph Strobl * @since 1.3 */ +@EqualsAndHashCode public class RedisClientInfo { - public static enum INFO { - ADDRESS_PORT("addr"), FILE_DESCRIPTOR("fd"), CONNECTION_NAME("name"), CONNECTION_AGE("age"), CONNECTION_IDLE("idle"), FLAGS( - "flags"), DATABSE_ID("db"), CHANNEL_SUBSCRIBTIONS("sub"), PATTERN_SUBSCRIBTIONS("psub"), MULIT_COMMAND_CONTEXT( - "multi"), BUFFER_LENGTH("qbuf"), BUFFER_FREE_SPACE("qbuf-free"), OUTPUT_BUFFER_LENGTH("obl"), OUTPUT_LIST_LENGTH( - "oll"), OUTPUT_BUFFER_MEMORY_USAGE("omem"), EVENTS("events"), LAST_COMMAND("cmd"); + public enum INFO { - String key; + ADDRESS_PORT("addr"), FILE_DESCRIPTOR("fd"), CONNECTION_NAME("name"), CONNECTION_AGE("age"), // + CONNECTION_IDLE("idle"), FLAGS("flags"), DATABSE_ID("db"), CHANNEL_SUBSCRIBTIONS("sub"), // + PATTERN_SUBSCRIBTIONS("psub"), MULIT_COMMAND_CONTEXT("multi"), BUFFER_LENGTH("qbuf"), // + BUFFER_FREE_SPACE("qbuf-free"), OUTPUT_BUFFER_LENGTH("obl"), OUTPUT_LIST_LENGTH("oll"), // + OUTPUT_BUFFER_MEMORY_USAGE("omem"), EVENTS("events"), LAST_COMMAND("cmd"); + + final String key; INFO(String key) { this.key = key; @@ -45,16 +51,22 @@ public class RedisClientInfo { private final Properties clientProperties; + /** + * Create {@link RedisClientInfo} from {@link Properties}. + * + * @param properties must not be {@literal null}. + */ public RedisClientInfo(Properties properties) { Assert.notNull(properties, "Cannot initialize client information for given 'null' properties."); + this.clientProperties = new Properties(); this.clientProperties.putAll(properties); } /** * Get address/port of the client. - * + * * @return */ public String getAddressPort() { @@ -63,7 +75,7 @@ public class RedisClientInfo { /** * Get file descriptor corresponding to the socket - * + * * @return */ public String getFileDescriptor() { @@ -72,7 +84,7 @@ public class RedisClientInfo { /** * Get the clients name. - * + * * @return */ public String getName() { @@ -81,7 +93,7 @@ public class RedisClientInfo { /** * Get total duration of the connection in seconds. - * + * * @return */ public Long getAge() { @@ -90,7 +102,7 @@ public class RedisClientInfo { /** * Get idle time of the connection in seconds. - * + * * @return */ public Long getIdle() { @@ -99,7 +111,7 @@ public class RedisClientInfo { /** * Get client flags. - * + * * @return */ public String getFlags() { @@ -108,7 +120,7 @@ public class RedisClientInfo { /** * Get current database index. - * + * * @return */ public Long getDatabaseId() { @@ -117,7 +129,7 @@ public class RedisClientInfo { /** * Get number of channel subscriptions. - * + * * @return */ public Long getChannelSubscribtions() { @@ -126,7 +138,7 @@ public class RedisClientInfo { /** * Get number of pattern subscriptions. - * + * * @return */ public Long getPatternSubscrbtions() { @@ -135,7 +147,7 @@ public class RedisClientInfo { /** * Get the number of commands in a MULTI/EXEC context. - * + * * @return */ public Long getMultiCommandContext() { @@ -144,7 +156,7 @@ public class RedisClientInfo { /** * Get the query buffer length. - * + * * @return */ public Long getBufferLength() { @@ -153,7 +165,7 @@ public class RedisClientInfo { /** * Get the free space of the query buffer. - * + * * @return */ public Long getBufferFreeSpace() { @@ -162,7 +174,7 @@ public class RedisClientInfo { /** * Get the output buffer length. - * + * * @return */ public Long getOutputBufferLength() { @@ -171,7 +183,7 @@ public class RedisClientInfo { /** * Get number queued replies in output buffer. - * + * * @return */ public Long getOutputListLength() { @@ -180,7 +192,7 @@ public class RedisClientInfo { /** * Get output buffer memory usage. - * + * * @return */ public Long getOutputBufferMemoryUsage() { @@ -189,7 +201,7 @@ public class RedisClientInfo { /** * Get file descriptor events. - * + * * @return */ public String getEvents() { @@ -198,7 +210,7 @@ public class RedisClientInfo { /** * Get last command played. - * + * * @return */ public String getLastCommand() { @@ -212,13 +224,14 @@ public class RedisClientInfo { public String get(INFO info) { Assert.notNull(info, "Cannot retrieve client information for 'null'."); - return get(info.key); + return this.clientProperties.getProperty(info.key); } /** * @param key must not be {@literal null} or {@literal empty}. * @return {@literal null} if no entry found for requested {@code key}. */ + @Nullable public String get(String key) { Assert.hasText(key, "Cannot get client information for 'empty' / 'null' key."); @@ -231,6 +244,10 @@ public class RedisClientInfo { return value == null ? null : Long.valueOf(value); } + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ @Override public String toString() { return this.clientProperties.toString(); @@ -245,41 +262,10 @@ public class RedisClientInfo { try { properties.load(new StringReader(source.replace(' ', '\n'))); } catch (IOException e) { - throw new IllegalArgumentException(String.format("Properties could not be loaded from String '%s'.", source), e); + throw new IllegalArgumentException(String.format("Properties could not be loaded from String '%s'.", source), + e); } return new RedisClientInfo(properties); } - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((clientProperties == null) ? 0 : clientProperties.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof RedisClientInfo)) { - return false; - } - RedisClientInfo other = (RedisClientInfo) obj; - if (clientProperties == null) { - if (other.clientProperties != null) { - return false; - } - } else if (!clientProperties.equals(other.clientProperties)) { - return false; - } - return true; - } - } diff --git a/src/main/java/org/springframework/data/redis/core/types/package-info.java b/src/main/java/org/springframework/data/redis/core/types/package-info.java index 64571585d..4386200f7 100644 --- a/src/main/java/org/springframework/data/redis/core/types/package-info.java +++ b/src/main/java/org/springframework/data/redis/core/types/package-info.java @@ -2,4 +2,5 @@ * Redis domain specific types. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.core.types; diff --git a/src/main/java/org/springframework/data/redis/hash/BeanUtilsHashMapper.java b/src/main/java/org/springframework/data/redis/hash/BeanUtilsHashMapper.java index b9784c256..fa50143ff 100644 --- a/src/main/java/org/springframework/data/redis/hash/BeanUtilsHashMapper.java +++ b/src/main/java/org/springframework/data/redis/hash/BeanUtilsHashMapper.java @@ -26,24 +26,37 @@ import org.apache.commons.beanutils.BeanUtils; * * @author Costin Leau * @author Christoph Strobl + * @author Mark Paluch */ public class BeanUtilsHashMapper implements HashMapper { - private Class type; + private final Class type; + /** + * Create a new {@link BeanUtilsHashMapper} for the given {@code type}. + * + * @param type must not be {@literal null}. + */ public BeanUtilsHashMapper(Class type) { this.type = type; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.hash.HashMapper#fromHash(java.util.Map) + */ + @Override public T fromHash(Map hash) { - T instance = org.springframework.beans.BeanUtils.instantiate(type); + T instance = org.springframework.beans.BeanUtils.instantiateClass(type); + try { + BeanUtils.populate(instance, hash); + return instance; } catch (Exception ex) { throw new RuntimeException(ex); } - return instance; } /* @@ -52,11 +65,12 @@ public class BeanUtilsHashMapper implements HashMapper { */ @Override public Map toHash(T object) { + try { Map map = BeanUtils.describe(object); - Map result = new LinkedHashMap<>(); + for (Entry entry : map.entrySet()) { if (entry.getValue() != null) { result.put(entry.getKey(), entry.getValue()); @@ -64,7 +78,6 @@ public class BeanUtilsHashMapper implements HashMapper { } return result; - } catch (Exception ex) { throw new IllegalArgumentException("Cannot describe object " + object, ex); } diff --git a/src/main/java/org/springframework/data/redis/hash/DecoratingStringHashMapper.java b/src/main/java/org/springframework/data/redis/hash/DecoratingStringHashMapper.java index 4897a6269..39e9aabe2 100644 --- a/src/main/java/org/springframework/data/redis/hash/DecoratingStringHashMapper.java +++ b/src/main/java/org/springframework/data/redis/hash/DecoratingStringHashMapper.java @@ -32,18 +32,29 @@ public class DecoratingStringHashMapper implements HashMapper toHash(T object) { + Map hash = delegate.toHash(object); Map flatten = new LinkedHashMap<>(hash.size()); for (Map.Entry entry : hash.entrySet()) { flatten.put(String.valueOf(entry.getKey()), String.valueOf(entry.getValue())); } + return flatten; } } diff --git a/src/main/java/org/springframework/data/redis/hash/Jackson2HashMapper.java b/src/main/java/org/springframework/data/redis/hash/Jackson2HashMapper.java index d6720dbe5..b5939d4a2 100644 --- a/src/main/java/org/springframework/data/redis/hash/Jackson2HashMapper.java +++ b/src/main/java/org/springframework/data/redis/hash/Jackson2HashMapper.java @@ -33,9 +33,7 @@ import org.springframework.util.StringUtils; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; -import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping; @@ -154,10 +152,6 @@ public class Jackson2HashMapper implements HashMapper { return typingMapper.treeToValue(untypedMapper.valueToTree(hash), Object.class); - } catch (JsonParseException e) { - throw new MappingException(e.getMessage(), e); - } catch (JsonMappingException e) { - throw new MappingException(e.getMessage(), e); } catch (IOException e) { throw new MappingException(e.getMessage(), e); } @@ -280,7 +274,7 @@ public class Jackson2HashMapper implements HashMapper { @SuppressWarnings("unchecked") private void appendValueToTypedList(String key, Object value, List destination) { - int index = Integer.valueOf(key.substring(key.indexOf('[') + 1, key.length() - 1)).intValue(); + int index = Integer.valueOf(key.substring(key.indexOf('[') + 1, key.length() - 1)); List resultList = ((List) destination.get(1)); if (resultList.size() < index) { resultList.add(value); 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 4cd2899c7..4f49c670e 100644 --- a/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java +++ b/src/main/java/org/springframework/data/redis/hash/ObjectHashMapper.java @@ -28,6 +28,7 @@ import org.springframework.data.redis.core.convert.RedisData; import org.springframework.data.redis.core.convert.ReferenceResolver; import org.springframework.data.redis.core.mapping.RedisMappingContext; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; /** * {@link HashMapper} based on {@link MappingRedisConverter}. Supports nested properties and simple types like @@ -94,7 +95,7 @@ public class ObjectHashMapper implements HashMapper { * @param customConversions can be {@literal null}. * @since 2.0 */ - public ObjectHashMapper(org.springframework.data.convert.CustomConversions customConversions) { + public ObjectHashMapper(@Nullable org.springframework.data.convert.CustomConversions customConversions) { MappingRedisConverter mappingConverter = new MappingRedisConverter(new RedisMappingContext(), new NoOpIndexResolver(), new NoOpReferenceResolver()); diff --git a/src/main/java/org/springframework/data/redis/hash/package-info.java b/src/main/java/org/springframework/data/redis/hash/package-info.java index 358dfbc10..9ad6ab381 100644 --- a/src/main/java/org/springframework/data/redis/hash/package-info.java +++ b/src/main/java/org/springframework/data/redis/hash/package-info.java @@ -2,4 +2,5 @@ * Dedicated support package for Redis hashes. Provides mapping of objects to hashes/maps (and vice versa). */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.hash; diff --git a/src/main/java/org/springframework/data/redis/listener/ChannelTopic.java b/src/main/java/org/springframework/data/redis/listener/ChannelTopic.java index f64a6fd0b..1ae7bb5f6 100644 --- a/src/main/java/org/springframework/data/redis/listener/ChannelTopic.java +++ b/src/main/java/org/springframework/data/redis/listener/ChannelTopic.java @@ -1,12 +1,12 @@ /* - * Copyright 2011-2013 the original author or authors. - * + * Copyright 2011-2017 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 - * + * * http://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. @@ -15,63 +15,45 @@ */ package org.springframework.data.redis.listener; +import lombok.EqualsAndHashCode; + import org.springframework.util.Assert; /** * Channel topic implementation (maps to a Redis channel). - * + * * @author Costin Leau + * @author Mark Paluch */ +@EqualsAndHashCode public class ChannelTopic implements Topic { private final String channelName; /** - * Constructs a new ChannelTopic instance. - * - * @param name + * Constructs a new {@link ChannelTopic} instance. + * + * @param name must not be {@literal null}. */ public ChannelTopic(String name) { - Assert.notNull(name, "a valid topic is required"); + + Assert.notNull(name, "Topic name must not be null!"); + this.channelName = name; } /** - * Returns the topic name. - * - * @return topic name + * @return topic name. */ + @Override public String getTopic() { return channelName; } - @Override - public int hashCode() { - return channelName.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof ChannelTopic)) { - return false; - } - ChannelTopic other = (ChannelTopic) obj; - if (channelName == null) { - if (other.channelName != null) { - return false; - } - } else if (!channelName.equals(other.channelName)) { - return false; - } - return true; - } - + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ @Override public String toString() { return channelName; diff --git a/src/main/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListener.java b/src/main/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListener.java index 8d047af3b..40e1086ce 100644 --- a/src/main/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListener.java +++ b/src/main/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListener.java @@ -25,19 +25,20 @@ import org.springframework.lang.Nullable; /** * {@link MessageListener} publishing {@link RedisKeyExpiredEvent}s via {@link ApplicationEventPublisher} by listening * to Redis keyspace notifications for key expirations. - * + * * @author Christoph Strobl * @since 1.7 */ public class KeyExpirationEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware { - private @Nullable ApplicationEventPublisher publisher; private static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic("__keyevent@*__:expired"); + private @Nullable ApplicationEventPublisher publisher; + /** * Creates new {@link MessageListener} for {@code __keyevent@*__:expired} messages. - * + * * @param listenerContainer must not be {@literal null}. */ public KeyExpirationEventMessageListener(RedisMessageListenerContainer listenerContainer) { @@ -64,12 +65,12 @@ public class KeyExpirationEventMessageListener extends KeyspaceEventMessageListe /** * Publish the event in case an {@link ApplicationEventPublisher} is set. - * + * * @param event can be {@literal null}. */ protected void publishEvent(RedisKeyExpiredEvent event) { - if (publisher != null && event != null) { + if (publisher != null) { this.publisher.publishEvent(event); } } diff --git a/src/main/java/org/springframework/data/redis/listener/KeyspaceEventMessageListener.java b/src/main/java/org/springframework/data/redis/listener/KeyspaceEventMessageListener.java index 7b5c92cc9..0c9d24baf 100644 --- a/src/main/java/org/springframework/data/redis/listener/KeyspaceEventMessageListener.java +++ b/src/main/java/org/springframework/data/redis/listener/KeyspaceEventMessageListener.java @@ -36,8 +36,10 @@ import org.springframework.util.StringUtils; */ public abstract class KeyspaceEventMessageListener implements MessageListener, InitializingBean, DisposableBean { - private final RedisMessageListenerContainer listenerContainer; private static final Topic TOPIC_ALL_KEYEVENTS = new PatternTopic("__keyevent@*"); + + private final RedisMessageListenerContainer listenerContainer; + private String keyspaceNotificationsConfigParameter = "EA"; /** diff --git a/src/main/java/org/springframework/data/redis/listener/PatternTopic.java b/src/main/java/org/springframework/data/redis/listener/PatternTopic.java index e4052f969..6dfec8742 100644 --- a/src/main/java/org/springframework/data/redis/listener/PatternTopic.java +++ b/src/main/java/org/springframework/data/redis/listener/PatternTopic.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2013 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 - * + * * http://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. @@ -15,53 +15,45 @@ */ package org.springframework.data.redis.listener; +import lombok.EqualsAndHashCode; + import org.springframework.util.Assert; /** * Pattern topic (matching multiple channels). - * + * * @author Costin Leau + * @author Mark Paluch */ +@EqualsAndHashCode public class PatternTopic implements Topic { private final String channelPattern; + /** + * Constructs a new {@link PatternTopic} instance. + * + * @param pattern must not be {@literal null}. + */ public PatternTopic(String pattern) { - Assert.notNull(pattern, "a valid topic is required"); + + Assert.notNull(pattern, "Pattern must not be null!"); + this.channelPattern = pattern; } + /** + * @return channel pattern. + */ + @Override public String getTopic() { return channelPattern; } - @Override - public int hashCode() { - return channelPattern.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof PatternTopic)) { - return false; - } - PatternTopic other = (PatternTopic) obj; - if (channelPattern == null) { - if (other.channelPattern != null) { - return false; - } - } else if (!channelPattern.equals(other.channelPattern)) { - return false; - } - return true; - } - + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ @Override public String toString() { return channelPattern; diff --git a/src/main/java/org/springframework/data/redis/listener/adapter/MessageListenerAdapter.java b/src/main/java/org/springframework/data/redis/listener/adapter/MessageListenerAdapter.java index 8176953e7..e9e22e943 100644 --- a/src/main/java/org/springframework/data/redis/listener/adapter/MessageListenerAdapter.java +++ b/src/main/java/org/springframework/data/redis/listener/adapter/MessageListenerAdapter.java @@ -104,14 +104,14 @@ public class MessageListenerAdapter implements InitializingBean, MessageListener private Set methods; private boolean lenient; - MethodInvoker(Object delegate, final String methodName) { + MethodInvoker(Object delegate, String methodName) { this.delegate = delegate; this.methodName = methodName; this.lenient = delegate instanceof MessageListener; this.methods = new HashSet<>(); - final Class c = delegate.getClass(); + Class c = delegate.getClass(); ReflectionUtils.doWithMethods(c, method -> { ReflectionUtils.makeAccessible(method); diff --git a/src/main/java/org/springframework/data/redis/listener/adapter/package-info.java b/src/main/java/org/springframework/data/redis/listener/adapter/package-info.java index 37aa45274..5172085aa 100644 --- a/src/main/java/org/springframework/data/redis/listener/adapter/package-info.java +++ b/src/main/java/org/springframework/data/redis/listener/adapter/package-info.java @@ -3,4 +3,5 @@ * appropriate message content types (such as String or byte array) that get passed into listener methods. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.listener.adapter; diff --git a/src/main/java/org/springframework/data/redis/listener/package-info.java b/src/main/java/org/springframework/data/redis/listener/package-info.java index 52912f83b..3754a1aed 100644 --- a/src/main/java/org/springframework/data/redis/listener/package-info.java +++ b/src/main/java/org/springframework/data/redis/listener/package-info.java @@ -2,4 +2,5 @@ * Base package for Redis message listener / pubsub container facility */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.listener; diff --git a/src/main/java/org/springframework/data/redis/package-info.java b/src/main/java/org/springframework/data/redis/package-info.java index bd4936a42..788c2e031 100644 --- a/src/main/java/org/springframework/data/redis/package-info.java +++ b/src/main/java/org/springframework/data/redis/package-info.java @@ -4,4 +4,5 @@ * Provides Redis specific exception hierarchy on top of the {@code org.springframework.dao} package. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis; diff --git a/src/main/java/org/springframework/data/redis/repository/cdi/RedisKeyValueAdapterBean.java b/src/main/java/org/springframework/data/redis/repository/cdi/RedisKeyValueAdapterBean.java index 534212eac..7f7e55da1 100644 --- a/src/main/java/org/springframework/data/redis/repository/cdi/RedisKeyValueAdapterBean.java +++ b/src/main/java/org/springframework/data/redis/repository/cdi/RedisKeyValueAdapterBean.java @@ -27,7 +27,6 @@ import javax.enterprise.inject.spi.BeanManager; import org.springframework.beans.factory.DisposableBean; import org.springframework.data.redis.core.RedisKeyValueAdapter; -import org.springframework.data.redis.core.RedisKeyValueTemplate; import org.springframework.data.redis.core.RedisOperations; import org.springframework.util.Assert; @@ -65,10 +64,7 @@ public class RedisKeyValueAdapterBean extends CdiBean { Type beanType = getBeanType(); - RedisOperations redisOperations = getDependencyInstance(this.redisOperations, beanType); - RedisKeyValueAdapter redisKeyValueAdapter = new RedisKeyValueAdapter(redisOperations); - - return redisKeyValueAdapter; + return new RedisKeyValueAdapter(getDependencyInstance(this.redisOperations, beanType)); } private Type getBeanType() { diff --git a/src/main/java/org/springframework/data/redis/repository/cdi/RedisKeyValueTemplateBean.java b/src/main/java/org/springframework/data/redis/repository/cdi/RedisKeyValueTemplateBean.java index 5e932b15e..850001a48 100644 --- a/src/main/java/org/springframework/data/redis/repository/cdi/RedisKeyValueTemplateBean.java +++ b/src/main/java/org/springframework/data/redis/repository/cdi/RedisKeyValueTemplateBean.java @@ -67,8 +67,7 @@ public class RedisKeyValueTemplateBean extends CdiBean { RedisMappingContext redisMappingContext = new RedisMappingContext(); redisMappingContext.afterPropertiesSet(); - RedisKeyValueTemplate redisKeyValueTemplate = new RedisKeyValueTemplate(keyValueAdapter, redisMappingContext); - return redisKeyValueTemplate; + return new RedisKeyValueTemplate(keyValueAdapter, redisMappingContext); } @Override diff --git a/src/main/java/org/springframework/data/redis/repository/cdi/RedisRepositoryBean.java b/src/main/java/org/springframework/data/redis/repository/cdi/RedisRepositoryBean.java index 2219a4081..e6f8aa3b2 100644 --- a/src/main/java/org/springframework/data/redis/repository/cdi/RedisRepositoryBean.java +++ b/src/main/java/org/springframework/data/redis/repository/cdi/RedisRepositoryBean.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.redis.repository.cdi; import java.lang.annotation.Annotation; @@ -29,6 +28,7 @@ import org.springframework.data.redis.repository.query.RedisQueryCreator; import org.springframework.data.redis.repository.support.RedisRepositoryFactory; import org.springframework.data.repository.cdi.CdiRepositoryBean; import org.springframework.data.repository.config.CustomRepositoryImplementationDetector; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -43,7 +43,7 @@ public class RedisRepositoryBean extends CdiRepositoryBean { /** * Creates a new {@link CdiRepositoryBean}. - * + * * @param keyValueTemplate must not be {@literal null}. * @param qualifiers must not be {@literal null}. * @param repositoryType must not be {@literal null}. @@ -52,7 +52,7 @@ public class RedisRepositoryBean extends CdiRepositoryBean { * {@link CustomRepositoryImplementationDetector}, can be {@literal null}. */ public RedisRepositoryBean(Bean keyValueTemplate, Set qualifiers, - Class repositoryType, BeanManager beanManager, CustomRepositoryImplementationDetector detector) { + Class repositoryType, BeanManager beanManager, @Nullable CustomRepositoryImplementationDetector detector) { super(qualifiers, repositoryType, beanManager, Optional.ofNullable(detector)); Assert.notNull(keyValueTemplate, "Bean holding keyvalue template must not be null!"); @@ -65,7 +65,8 @@ public class RedisRepositoryBean extends CdiRepositoryBean { KeyValueOperations keyValueTemplate = getDependencyInstance(this.keyValueTemplate, KeyValueOperations.class); RedisRepositoryFactory factory = new RedisRepositoryFactory(keyValueTemplate, RedisQueryCreator.class); - return customImplementation.isPresent() ? factory.getRepository(repositoryType, customImplementation.get()) : factory.getRepository(repositoryType); + return customImplementation.map(o -> factory.getRepository(repositoryType, o)) + .orElseGet(() -> factory.getRepository(repositoryType)); } } diff --git a/src/main/java/org/springframework/data/redis/repository/cdi/package-info.java b/src/main/java/org/springframework/data/redis/repository/cdi/package-info.java index 97d838c0b..a49f50514 100644 --- a/src/main/java/org/springframework/data/redis/repository/cdi/package-info.java +++ b/src/main/java/org/springframework/data/redis/repository/cdi/package-info.java @@ -2,4 +2,5 @@ * CDI support for Redis specific repository implementation. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.repository.cdi; diff --git a/src/main/java/org/springframework/data/redis/repository/configuration/package-info.java b/src/main/java/org/springframework/data/redis/repository/configuration/package-info.java index 33682f5ac..cead482e9 100644 --- a/src/main/java/org/springframework/data/redis/repository/configuration/package-info.java +++ b/src/main/java/org/springframework/data/redis/repository/configuration/package-info.java @@ -2,4 +2,5 @@ * Redis repository specific configuration and bean registration. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.repository.configuration; diff --git a/src/main/java/org/springframework/data/redis/repository/core/MappingRedisEntityInformation.java b/src/main/java/org/springframework/data/redis/repository/core/MappingRedisEntityInformation.java index 90794808d..7266799d1 100644 --- a/src/main/java/org/springframework/data/redis/repository/core/MappingRedisEntityInformation.java +++ b/src/main/java/org/springframework/data/redis/repository/core/MappingRedisEntityInformation.java @@ -32,17 +32,14 @@ import org.springframework.data.repository.core.support.PersistentEntityInformat public class MappingRedisEntityInformation extends PersistentEntityInformation implements RedisEntityInformation { - private final RedisPersistentEntity entityMetadata; - /** * @param entity */ public MappingRedisEntityInformation(RedisPersistentEntity entity) { + super(entity); - this.entityMetadata = entity; - - if (!entityMetadata.hasIdProperty()) { + if (!entity.hasIdProperty()) { throw new MappingException( String.format("Entity %s requires to have an explicit id field. Did you forget to provide one using @Id?", diff --git a/src/main/java/org/springframework/data/redis/repository/core/package-info.java b/src/main/java/org/springframework/data/redis/repository/core/package-info.java index 72facbc20..8437bf21b 100644 --- a/src/main/java/org/springframework/data/redis/repository/core/package-info.java +++ b/src/main/java/org/springframework/data/redis/repository/core/package-info.java @@ -2,4 +2,5 @@ * Core domain entities for repository support. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.repository.core; \ No newline at end of file diff --git a/src/main/java/org/springframework/data/redis/repository/package-info.java b/src/main/java/org/springframework/data/redis/repository/package-info.java index db7ca62a1..ce2277922 100644 --- a/src/main/java/org/springframework/data/redis/repository/package-info.java +++ b/src/main/java/org/springframework/data/redis/repository/package-info.java @@ -2,4 +2,5 @@ * Redis specific implementation of repository support */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.repository; diff --git a/src/main/java/org/springframework/data/redis/repository/query/RedisOperationChain.java b/src/main/java/org/springframework/data/redis/repository/query/RedisOperationChain.java index c7c736489..505f35e1d 100644 --- a/src/main/java/org/springframework/data/redis/repository/query/RedisOperationChain.java +++ b/src/main/java/org/springframework/data/redis/repository/query/RedisOperationChain.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.repository.query; +import lombok.EqualsAndHashCode; + import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -26,7 +28,6 @@ import org.springframework.data.geo.Distance; import org.springframework.data.geo.Point; import org.springframework.lang.Nullable; import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; /** * Simple set of operations required to run queries against Redis. @@ -36,8 +37,9 @@ import org.springframework.util.ObjectUtils; */ public class RedisOperationChain { - private Set sismember = new LinkedHashSet<>(); - private Set orSismember = new LinkedHashSet<>(); + private final Set sismember = new LinkedHashSet<>(); + private final Set orSismember = new LinkedHashSet<>(); + private @Nullable NearPath near; public void sismember(String path, Object value) { @@ -79,6 +81,7 @@ public class RedisOperationChain { return near; } + @EqualsAndHashCode public static class PathAndValue { private final String path; @@ -108,6 +111,7 @@ public class RedisOperationChain { return values; } + @Nullable public Object getFirstValue() { return values.isEmpty() ? null : values.iterator().next(); } @@ -116,34 +120,6 @@ public class RedisOperationChain { public String toString() { return path + ":" + (isSingleValue() ? getFirstValue() : values); } - - @Override - public int hashCode() { - - int result = ObjectUtils.nullSafeHashCode(path); - result += ObjectUtils.nullSafeHashCode(values); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof PathAndValue)) { - return false; - } - PathAndValue that = (PathAndValue) obj; - if (!ObjectUtils.nullSafeEquals(this.path, that.path)) { - return false; - } - - return ObjectUtils.nullSafeEquals(this.values, that.values); - } - } /** diff --git a/src/main/java/org/springframework/data/redis/repository/query/RedisQueryCreator.java b/src/main/java/org/springframework/data/redis/repository/query/RedisQueryCreator.java index fbb82cd61..51a11d501 100644 --- a/src/main/java/org/springframework/data/redis/repository/query/RedisQueryCreator.java +++ b/src/main/java/org/springframework/data/redis/repository/query/RedisQueryCreator.java @@ -106,7 +106,7 @@ public class RedisQueryCreator extends AbstractQueryCreator implements RedisElementWriter { public ByteBuffer write(T value) { if (serializer != null) { - return ByteBuffer.wrap(serializer.serialize((T) value)); + return ByteBuffer.wrap(serializer.serialize(value)); } if (value instanceof byte[]) { diff --git a/src/main/java/org/springframework/data/redis/serializer/DefaultSerializationPair.java b/src/main/java/org/springframework/data/redis/serializer/DefaultSerializationPair.java index 80a56970c..88e835fb4 100644 --- a/src/main/java/org/springframework/data/redis/serializer/DefaultSerializationPair.java +++ b/src/main/java/org/springframework/data/redis/serializer/DefaultSerializationPair.java @@ -16,6 +16,7 @@ package org.springframework.data.redis.serializer; import lombok.Getter; + import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; /** @@ -32,7 +33,7 @@ class DefaultSerializationPair implements SerializationPair { private final RedisElementWriter writer; @SuppressWarnings("unchecked") - protected DefaultSerializationPair(RedisElementReader reader, RedisElementWriter writer) { + DefaultSerializationPair(RedisElementReader reader, RedisElementWriter writer) { this.reader = (RedisElementReader) reader; this.writer = (RedisElementWriter) writer; diff --git a/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java b/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java index f9ac7ad19..e76a3e4c2 100644 --- a/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java @@ -52,10 +52,10 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer T deserialize(@Nullable byte[] source, Class type) throws SerializationException { Assert.notNull(type, @@ -147,7 +148,7 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializerNote: The conversion service initialization happens automatically if the class is defined as a Spring * bean. Note: Does not handle nulls in any special way delegating everything to the container. - * + * * @author Costin Leau * @author Christoph Strobl + * @author Mark Paluch */ public class GenericToStringSerializer implements RedisSerializer, BeanFactoryAware { + private final Class type; private final Charset charset; + private Converter converter = new Converter(new DefaultConversionService()); - private Class type; public GenericToStringSerializer(Class type) { - this(type, Charset.forName("UTF8")); + this(type, StandardCharsets.UTF_8); } public GenericToStringSerializer(Class type, Charset charset) { - Assert.notNull(type, "tyoe must not be null!"); + + Assert.notNull(type, "Type must not be null!"); + this.type = type; this.charset = charset; } public void setConversionService(ConversionService conversionService) { + Assert.notNull(conversionService, "non null conversion service required"); converter = new Converter(conversionService); } public void setTypeConverter(TypeConverter typeConverter) { + Assert.notNull(typeConverter, "non null type converter required"); converter = new Converter(typeConverter); } @@ -83,6 +90,8 @@ public class GenericToStringSerializer implements RedisSerializer, BeanFac } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + + // TODO: This code can never happen... if (converter == null && beanFactory instanceof ConfigurableBeanFactory) { ConfigurableBeanFactory cFB = (ConfigurableBeanFactory) beanFactory; ConversionService conversionService = cFB.getConversionService(); diff --git a/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java b/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java index 82eea9b32..20f08cf68 100644 --- a/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2014 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 - * + * * http://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. @@ -16,6 +16,7 @@ package org.springframework.data.redis.serializer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -26,19 +27,19 @@ import com.fasterxml.jackson.databind.ser.SerializerFactory; import com.fasterxml.jackson.databind.type.TypeFactory; /** - * {@link RedisSerializer} that can read and write JSON using Jackson's and Jackson Databind {@link ObjectMapper}. + * {@link RedisSerializer} that can read and write JSON using + * Jackson's and + * Jackson Databind {@link ObjectMapper}. *

* This converter can be used to bind to typed beans, or untyped {@link java.util.HashMap HashMap} instances. * Note:Null objects are serialized as empty arrays and vice versa. - * + * * @author Thomas Darimont * @since 1.2 */ public class Jackson2JsonRedisSerializer implements RedisSerializer { - public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; private final JavaType javaType; @@ -46,7 +47,7 @@ public class Jackson2JsonRedisSerializer implements RedisSerializer { /** * Creates a new {@link Jackson2JsonRedisSerializer} for the given target {@link Class}. - * + * * @param type */ public Jackson2JsonRedisSerializer(Class type) { @@ -55,7 +56,7 @@ public class Jackson2JsonRedisSerializer implements RedisSerializer { /** * Creates a new {@link Jackson2JsonRedisSerializer} for the given target {@link JavaType}. - * + * * @param javaType */ public Jackson2JsonRedisSerializer(JavaType javaType) { @@ -108,7 +109,7 @@ public class Jackson2JsonRedisSerializer implements RedisSerializer { *

* Default implementation returns {@link TypeFactory#constructType(java.lang.reflect.Type)}, but this can be * overridden in subclasses, to allow for custom generic collection handling. For instance: - * + * *

 	 * protected JavaType getJavaType(Class<?> clazz) {
 	 * 	if (List.class.isAssignableFrom(clazz)) {
@@ -118,7 +119,7 @@ public class Jackson2JsonRedisSerializer implements RedisSerializer {
 	 * 	}
 	 * }
 	 * 
- * + * * @param clazz the class to return the java type for * @return the java type */ diff --git a/src/main/java/org/springframework/data/redis/serializer/OxmSerializer.java b/src/main/java/org/springframework/data/redis/serializer/OxmSerializer.java index 0ca7380ca..633d53c51 100644 --- a/src/main/java/org/springframework/data/redis/serializer/OxmSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/OxmSerializer.java @@ -1,12 +1,12 @@ /* - * Copyright 2011-2013 the original author or authors. - * + * Copyright 2011-2017 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 - * + * * http://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. @@ -29,35 +29,41 @@ import org.springframework.util.Assert; /** * Serializer adapter on top of Spring's O/X Mapping. Delegates serialization/deserialization to OXM {@link Marshaller} - * and {@link Unmarshaller}. Note:Null objects are serialized as empty arrays and vice versa. - * + * and {@link Unmarshaller}. Note: {@literal null} objects are serialized as empty arrays and vice versa. + * * @author Costin Leau + * @author Mark Paluch */ public class OxmSerializer implements InitializingBean, RedisSerializer { private @Nullable Marshaller marshaller; private @Nullable Unmarshaller unmarshaller; + /** + * Creates a new, uninitialized {@link OxmSerializer}. Requires {@link #setMarshaller(Marshaller)} and + * {@link #setUnmarshaller(Unmarshaller)} to be set before this serializer can be used. + */ public OxmSerializer() {} + /** + * Creates a new {@link OxmSerializer} given {@link Marshaller} and {@link Unmarshaller}. + * + * @param marshaller must not be {@literal null}. + * @param unmarshaller must not be {@literal null}. + */ public OxmSerializer(Marshaller marshaller, Unmarshaller unmarshaller) { - this.marshaller = marshaller; - this.unmarshaller = unmarshaller; - - afterPropertiesSet(); - } - - public void afterPropertiesSet() { - - Assert.notNull(marshaller, "non-null marshaller required"); // TODO: use Illegal state exception - Assert.notNull(unmarshaller, "non-null unmarshaller required"); + setMarshaller(marshaller); + setUnmarshaller(unmarshaller); } /** * @param marshaller The marshaller to set. */ public void setMarshaller(Marshaller marshaller) { + + Assert.notNull(marshaller, "Marshaller must not be null!"); + this.marshaller = marshaller; } @@ -65,11 +71,30 @@ public class OxmSerializer implements InitializingBean, RedisSerializer * @param unmarshaller The unmarshaller to set. */ public void setUnmarshaller(Unmarshaller unmarshaller) { + + Assert.notNull(unmarshaller, "Unmarshaller must not be null!"); + this.unmarshaller = unmarshaller; } + /* + * (non-Javadoc) + * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() { + + Assert.state(marshaller != null, "non-null marshaller required"); + Assert.state(unmarshaller != null, "non-null unmarshaller required"); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.serializer.RedisSerializer#deserialize(byte[]) + */ @Override public Object deserialize(@Nullable byte[] bytes) throws SerializationException { + if (SerializationUtils.isEmpty(bytes)) { return null; } @@ -81,8 +106,13 @@ public class OxmSerializer implements InitializingBean, RedisSerializer } } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.serializer.RedisSerializer#serialize(java.lang.Object) + */ @Override public byte[] serialize(@Nullable Object t) throws SerializationException { + if (t == null) { return SerializationUtils.EMPTY_ARRAY; } diff --git a/src/main/java/org/springframework/data/redis/serializer/RedisSerializerToSerializationPairAdapter.java b/src/main/java/org/springframework/data/redis/serializer/RedisSerializerToSerializationPairAdapter.java index 79e77c156..1fd7cbd61 100644 --- a/src/main/java/org/springframework/data/redis/serializer/RedisSerializerToSerializationPairAdapter.java +++ b/src/main/java/org/springframework/data/redis/serializer/RedisSerializerToSerializationPairAdapter.java @@ -16,6 +16,7 @@ package org.springframework.data.redis.serializer; import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -32,7 +33,7 @@ class RedisSerializerToSerializationPairAdapter implements SerializationPair< private final DefaultSerializationPair pair; - protected RedisSerializerToSerializationPairAdapter(RedisSerializer serializer) { + protected RedisSerializerToSerializationPairAdapter(@Nullable RedisSerializer serializer) { pair = new DefaultSerializationPair(new DefaultRedisElementReader<>(serializer), new DefaultRedisElementWriter<>(serializer)); } diff --git a/src/main/java/org/springframework/data/redis/serializer/SerializationException.java b/src/main/java/org/springframework/data/redis/serializer/SerializationException.java index 6397de261..0a49f1e5c 100644 --- a/src/main/java/org/springframework/data/redis/serializer/SerializationException.java +++ b/src/main/java/org/springframework/data/redis/serializer/SerializationException.java @@ -1,12 +1,12 @@ /* - * Copyright 2011-2013 the original author or authors. - * + * Copyright 2011-2017 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 - * + * * http://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. @@ -19,27 +19,28 @@ import org.springframework.core.NestedRuntimeException; /** * Generic exception indicating a serialization/deserialization error. - * + * * @author Costin Leau + * @author Mark Paluch */ public class SerializationException extends NestedRuntimeException { /** - * Constructs a new SerializationException instance. - * - * @param msg - * @param cause - */ - public SerializationException(String msg, Throwable cause) { - super(msg, cause); - } - - /** - * Constructs a new SerializationException instance. - * + * Constructs a new {@link SerializationException} instance. + * * @param msg */ public SerializationException(String msg) { super(msg); } + + /** + * Constructs a new {@link SerializationException} instance. + * + * @param msg the detail message. + * @param cause the nested exception. + */ + public SerializationException(String msg, Throwable cause) { + super(msg, cause); + } } diff --git a/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java b/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java index a5fcfeb4d..9413c7126 100644 --- a/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java +++ b/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java @@ -42,7 +42,7 @@ public abstract class SerializationUtils { @SuppressWarnings("unchecked") static > T deserializeValues(@Nullable Collection rawValues, Class type, - RedisSerializer redisSerializer) { + @Nullable RedisSerializer redisSerializer) { // connection in pipeline/multi mode if (rawValues == null) { return (T) CollectionFactory.createCollection(type, 0); @@ -58,12 +58,13 @@ public abstract class SerializationUtils { } @SuppressWarnings("unchecked") - public static Set deserialize(@Nullable Set rawValues, RedisSerializer redisSerializer) { + public static Set deserialize(@Nullable Set rawValues, @Nullable RedisSerializer redisSerializer) { return deserializeValues(rawValues, Set.class, redisSerializer); } @SuppressWarnings("unchecked") - public static List deserialize(@Nullable List rawValues, RedisSerializer redisSerializer) { + public static List deserialize(@Nullable List rawValues, + @Nullable RedisSerializer redisSerializer) { return deserializeValues(rawValues, List.class, redisSerializer); } @@ -87,7 +88,7 @@ public abstract class SerializationUtils { @SuppressWarnings("unchecked") public static Map deserialize(@Nullable Map rawValues, - RedisSerializer hashKeySerializer, RedisSerializer hashValueSerializer) { + @Nullable RedisSerializer hashKeySerializer, @Nullable RedisSerializer hashValueSerializer) { if (rawValues == null) { return Collections.emptyMap(); @@ -95,8 +96,8 @@ public abstract class SerializationUtils { Map map = new LinkedHashMap<>(rawValues.size()); for (Map.Entry entry : rawValues.entrySet()) { // May want to deserialize only key or value - HK key = hashKeySerializer != null ? (HK) hashKeySerializer.deserialize(entry.getKey()) : (HK) entry.getKey(); - HV value = hashValueSerializer != null ? (HV) hashValueSerializer.deserialize(entry.getValue()) + HK key = hashKeySerializer != null ? hashKeySerializer.deserialize(entry.getKey()) : (HK) entry.getKey(); + HV value = hashValueSerializer != null ? hashValueSerializer.deserialize(entry.getValue()) : (HV) entry.getValue(); map.put(key, value); } diff --git a/src/main/java/org/springframework/data/redis/serializer/StringRedisSerializer.java b/src/main/java/org/springframework/data/redis/serializer/StringRedisSerializer.java index 3c1a5c22a..417b0d03d 100644 --- a/src/main/java/org/springframework/data/redis/serializer/StringRedisSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/StringRedisSerializer.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2017 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 - * + * * http://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. @@ -16,6 +16,7 @@ package org.springframework.data.redis.serializer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -27,7 +28,7 @@ import org.springframework.util.Assert; * Useful when the interaction with the Redis happens mainly through Strings. *

* Does not perform any null conversion since empty strings are valid keys/values. - * + * * @author Costin Leau * @author Christoph Strobl */ @@ -35,19 +36,38 @@ public class StringRedisSerializer implements RedisSerializer { private final Charset charset; + /** + * Creates a new {@link StringRedisSerializer} using {@link StandardCharsets#UTF_8 UTF-8}. + */ public StringRedisSerializer() { - this(Charset.forName("UTF8")); + this(StandardCharsets.UTF_8); } + /** + * Creates a new {@link StringRedisSerializer} using the given {@link Charset} to encode and decode strings. + * + * @param charset must not be {@literal null}. + */ public StringRedisSerializer(Charset charset) { + Assert.notNull(charset, "Charset must not be null!"); this.charset = charset; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.serializer.RedisSerializer#deserialize(byte[]) + */ + @Override public String deserialize(@Nullable byte[] bytes) { return (bytes == null ? null : new String(bytes, charset)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.serializer.RedisSerializer#serialize(java.lang.Object) + */ + @Override public byte[] serialize(@Nullable String string) { return (string == null ? null : string.getBytes(charset)); } diff --git a/src/main/java/org/springframework/data/redis/serializer/package-info.java b/src/main/java/org/springframework/data/redis/serializer/package-info.java index f11776cf2..45801b579 100644 --- a/src/main/java/org/springframework/data/redis/serializer/package-info.java +++ b/src/main/java/org/springframework/data/redis/serializer/package-info.java @@ -2,4 +2,5 @@ * Serialization/Deserialization package for converting Object to (and from) binary data. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.serializer; diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java index ecd275c4a..999a08f56 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java @@ -31,6 +31,7 @@ import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.serializer.GenericToStringSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -47,31 +48,33 @@ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyO private static final long serialVersionUID = 1L; private volatile String key; - private ValueOperations operations; - private RedisOperations generalOps; + + private final ValueOperations operations; + private final RedisOperations generalOps; /** - * Constructs a new RedisAtomicDouble instance. Uses the value existing in Redis or 0 if none is found. + * Constructs a new {@link RedisAtomicDouble} instance. Uses the value existing in Redis or 0 if none is found. * - * @param redisCounter redis counter - * @param factory connection factory + * @param redisCounter Redis key of this counter. + * @param factory connection factory. */ public RedisAtomicDouble(String redisCounter, RedisConnectionFactory factory) { this(redisCounter, factory, null); } /** - * Constructs a new RedisAtomicDouble instance. + * Constructs a new {@link RedisAtomicDouble} instance. * - * @param redisCounter - * @param factory - * @param initialValue + * @param redisCounter Redis key of this counter. + * @param factory connection factory. + * @param initialValue initial value to set if the Redis key is absent. */ public RedisAtomicDouble(String redisCounter, RedisConnectionFactory factory, double initialValue) { this(redisCounter, factory, Double.valueOf(initialValue)); } - private RedisAtomicDouble(String redisCounter, RedisConnectionFactory factory, Double initialValue) { + private RedisAtomicDouble(String redisCounter, RedisConnectionFactory factory, @Nullable Double initialValue) { + Assert.hasText(redisCounter, "a valid counter name is required"); Assert.notNull(factory, "a valid factory is required"); @@ -96,10 +99,10 @@ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyO } /** - * Constructs a new RedisAtomicDouble instance. Uses the value existing in Redis or 0 if none is found. + * Constructs a new {@link RedisAtomicDouble} instance. Uses the value existing in Redis or 0 if none is found. * - * @param redisCounter the redis counter - * @param template the template + * @param redisCounter Redis key of this counter. + * @param template the template. * @see #RedisAtomicDouble(String, RedisConnectionFactory, double) */ public RedisAtomicDouble(String redisCounter, RedisOperations template) { @@ -107,20 +110,21 @@ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyO } /** - * Constructs a new RedisAtomicDouble instance. Note: You need to configure the given {@code template} - * with appropriate {@link RedisSerializer} for the key and value. As an alternative one could use the + * Constructs a new {@link RedisAtomicDouble} instance. Note: You need to configure the given {@code template} with + * appropriate {@link RedisSerializer} for the key and value. As an alternative one could use the * {@link #RedisAtomicDouble(String, RedisConnectionFactory, Double)} constructor which uses appropriate default * serializers. * - * @param redisCounter the redis counter + * @param redisCounter Redis key of this counter. * @param template the template - * @param initialValue the initial value + * @param initialValue initial value to set if the Redis key is absent. */ public RedisAtomicDouble(String redisCounter, RedisOperations template, double initialValue) { this(redisCounter, template, Double.valueOf(initialValue)); } - private RedisAtomicDouble(String redisCounter, RedisOperations template, Double initialValue) { + private RedisAtomicDouble(String redisCounter, RedisOperations template, + @Nullable Double initialValue) { Assert.hasText(redisCounter, "a valid counter name is required"); Assert.notNull(template, "a valid template is required"); @@ -143,7 +147,7 @@ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyO /** * Gets the current value. * - * @return the current value + * @return the current value. */ public double get() { @@ -158,7 +162,7 @@ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyO /** * Sets to the given value. * - * @param newValue the new value + * @param newValue the new value. */ public void set(double newValue) { operations.set(key, newValue); @@ -167,29 +171,29 @@ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyO /** * Atomically sets to the given value and returns the old value. * - * @param newValue the new value - * @return the previous value + * @param newValue the new value. + * @return the previous value. */ public double getAndSet(double newValue) { Double value = operations.getAndSet(key, newValue); - if (value != null) { - return value.doubleValue(); - } - return 0; + return value != null ? value.doubleValue() : 0; } /** * Atomically sets the value to the given updated value if the current value {@code ==} the expected value. * - * @param expect the expected value - * @param update the new value - * @return true if successful. False return indicates that the actual value was not equal to the expected value. + * @param expect the expected value. + * @param update the new value. + * @return {@literal true} if successful. {@literal false} indicates that the actual value was not equal to the + * expected value. */ public boolean compareAndSet(final double expect, final double update) { + return generalOps.execute(new SessionCallback() { + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public Boolean execute(RedisOperations operations) { for (;;) { @@ -266,60 +270,111 @@ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyO } /** - * Returns the String representation of the current value. - * * @return the String representation of the current value. */ + @Override public String toString() { return Double.toString(get()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getKey() + */ + @Override public String getKey() { return key; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getType() + */ + @Override public DataType getType() { return DataType.STRING; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getExpire() + */ + @Override public Long getExpire() { return generalOps.getExpire(key); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expire(long, java.util.concurrent.TimeUnit) + */ + @Override public Boolean expire(long timeout, TimeUnit unit) { return generalOps.expire(key, timeout, unit); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expireAt(java.util.Date) + */ + @Override public Boolean expireAt(Date date) { return generalOps.expireAt(key, date); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#persist() + */ + @Override public Boolean persist() { return generalOps.persist(key); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#rename(java.lang.Object) + */ + @Override public void rename(String newKey) { + generalOps.rename(key, newKey); key = newKey; } - @Override - public double doubleValue() { - return get(); - } - - @Override - public float floatValue() { - return (float) get(); - } - + /* + * (non-Javadoc) + * @see java.lang.Number#intValue() + */ @Override public int intValue() { return (int) get(); } + /* + * (non-Javadoc) + * @see java.lang.Number#longValue() + */ @Override public long longValue() { return (long) get(); } + + /* + * (non-Javadoc) + * @see java.lang.Number#floatValue() + */ + @Override + public float floatValue() { + return (float) get(); + } + + /* + * (non-Javadoc) + * @see java.lang.Number#doubleValue() + */ + @Override + public double doubleValue() { + return get(); + } } diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java index e1b185863..2e1641e84 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java @@ -31,52 +31,54 @@ import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.serializer.GenericToStringSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** * Atomic integer backed by Redis. Uses Redis atomic increment/decrement and watch/multi/exec operations for CAS * operations. * - * @see java.util.concurrent.atomic.AtomicInteger * @author Costin Leau * @author Thomas Darimont * @author Christoph Strobl * @author Mark Paluch + * @see java.util.concurrent.atomic.AtomicInteger */ public class RedisAtomicInteger extends Number implements Serializable, BoundKeyOperations { private static final long serialVersionUID = 1L; private volatile String key; - private ValueOperations operations; - private RedisOperations generalOps; + + private final ValueOperations operations; + private final RedisOperations generalOps; /** - * Constructs a new RedisAtomicInteger instance. Uses the value existing in Redis or 0 if none is found. + * Constructs a new {@link RedisAtomicInteger} instance. Uses the value existing in Redis or 0 if none is found. * - * @param redisCounter redis counter - * @param factory connection factory + * @param redisCounter Redis key of this counter. + * @param factory connection factory. */ public RedisAtomicInteger(String redisCounter, RedisConnectionFactory factory) { this(redisCounter, factory, null); } /** - * Constructs a new RedisAtomicInteger instance. + * Constructs a new {@link RedisAtomicInteger} instance. * - * @param redisCounter the redis counter - * @param factory the factory - * @param initialValue the initial value + * @param redisCounter Redis key of this counter. + * @param factory connection factory. + * @param initialValue initial value to set if the Redis key is absent. */ public RedisAtomicInteger(String redisCounter, RedisConnectionFactory factory, int initialValue) { this(redisCounter, factory, Integer.valueOf(initialValue)); } /** - * Constructs a new RedisAtomicInteger instance. Uses the value existing in Redis or 0 if none is found. + * Constructs a new {@link RedisAtomicInteger} instance. Uses the value existing in Redis or 0 if none is found. * - * @param redisCounter the redis counter - * @param template the template + * @param redisCounter Redis key of this counter. + * @param template the template. * @see #RedisAtomicInteger(String, RedisConnectionFactory, int) */ public RedisAtomicInteger(String redisCounter, RedisOperations template) { @@ -84,20 +86,21 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey } /** - * Constructs a new RedisAtomicInteger instance. Note: You need to configure the given {@code template} - * with appropriate {@link RedisSerializer} for the key and value. As an alternative one could use the + * Constructs a new {@link RedisAtomicInteger} instance. Note: You need to configure the given {@code template} with + * appropriate {@link RedisSerializer} for the key and value. As an alternative one could use the * {@link #RedisAtomicInteger(String, RedisConnectionFactory, Integer)} constructor which uses appropriate default * serializers. * - * @param redisCounter the redis counter - * @param template the template - * @param initialValue the initial value + * @param redisCounter Redis key of this counter. + * @param template the template. + * @param initialValue initial value to set if the Redis key is absent. */ public RedisAtomicInteger(String redisCounter, RedisOperations template, int initialValue) { this(redisCounter, template, Integer.valueOf(initialValue)); } - private RedisAtomicInteger(String redisCounter, RedisConnectionFactory factory, Integer initialValue) { + private RedisAtomicInteger(String redisCounter, RedisConnectionFactory factory, @Nullable Integer initialValue) { + RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericToStringSerializer<>(Integer.class)); @@ -118,7 +121,8 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey } } - private RedisAtomicInteger(String redisCounter, RedisOperations template, Integer initialValue) { + private RedisAtomicInteger(String redisCounter, RedisOperations template, + @Nullable Integer initialValue) { Assert.hasText(redisCounter, "a valid counter name is required"); Assert.notNull(template, "a valid template is required"); @@ -141,7 +145,7 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Get the current value. * - * @return the current value + * @return the current value. */ public int get() { @@ -156,7 +160,7 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Set to the given value. * - * @param newValue the new value + * @param newValue the new value. */ public void set(int newValue) { operations.set(key, newValue); @@ -165,29 +169,29 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Set to the give value and return the old value. * - * @param newValue the new value - * @return the previous value + * @param newValue the new value. + * @return the previous value. */ public int getAndSet(int newValue) { Integer value = operations.getAndSet(key, newValue); - if (value != null) { - return value.intValue(); - } - return 0; + return value != null ? value.intValue() : 0; } /** * Atomically set the value to the given updated value if the current value == the expected value. * - * @param expect the expected value - * @param update the new value - * @return true if successful. False return indicates that the actual value was not equal to the expected value. + * @param expect the expected value. + * @param update the new value. + * @return {@literal true} if successful. {@literal false} indicates that the actual value was not equal to the + * expected value. */ - public boolean compareAndSet(final int expect, final int update) { + public boolean compareAndSet(int expect, int update) { + return generalOps.execute(new SessionCallback() { + @Override @SuppressWarnings("unchecked") public Boolean execute(RedisOperations operations) { for (;;) { @@ -210,7 +214,7 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Atomically increment by one the current value. * - * @return the previous value + * @return the previous value. */ public int getAndIncrement() { return incrementAndGet() - 1; @@ -219,7 +223,7 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Atomically decrement by one the current value. * - * @return the previous value + * @return the previous value. */ public int getAndDecrement() { return decrementAndGet() + 1; @@ -228,8 +232,8 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Atomically add the given value to current value. * - * @param delta the value to add - * @return the previous value + * @param delta the value to add. + * @return the previous value. */ public int getAndAdd(final int delta) { return addAndGet(delta) - delta; @@ -238,7 +242,7 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Atomically increment by one the current value. * - * @return the updated value + * @return the updated value. */ public int incrementAndGet() { return operations.increment(key, 1).intValue(); @@ -247,7 +251,7 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Atomically decrement by one the current value. * - * @return the updated value + * @return the updated value. */ public int decrementAndGet() { return operations.increment(key, -1).intValue(); @@ -256,64 +260,119 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Atomically add the given value to current value. * - * @param delta the value to add - * @return the updated value + * @param delta the value to add. + * @return the updated value. */ public int addAndGet(int delta) { return operations.increment(key, delta).intValue(); } /** - * Returns the String representation of the current value. - * * @return the String representation of the current value. */ + @Override public String toString() { return Integer.toString(get()); } - public int intValue() { - return get(); - } - - public long longValue() { - return (long) get(); - } - - public float floatValue() { - return (float) get(); - } - - public double doubleValue() { - return (double) get(); - } - + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getKey() + */ + @Override public String getKey() { return key; } - public Boolean expire(long timeout, TimeUnit unit) { - return generalOps.expire(key, timeout, unit); - } - - public Boolean expireAt(Date date) { - return generalOps.expireAt(key, date); + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getType() + */ + @Override + public DataType getType() { + return DataType.STRING; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getExpire() + */ + @Override public Long getExpire() { return generalOps.getExpire(key); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expire(long, java.util.concurrent.TimeUnit) + */ + @Override + public Boolean expire(long timeout, TimeUnit unit) { + return generalOps.expire(key, timeout, unit); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expireAt(java.util.Date) + */ + @Override + public Boolean expireAt(Date date) { + return generalOps.expireAt(key, date); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#persist() + */ + @Override public Boolean persist() { return generalOps.persist(key); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#rename(java.lang.Object) + */ + @Override public void rename(String newKey) { + generalOps.rename(key, newKey); key = newKey; } - public DataType getType() { - return DataType.STRING; + /* + * (non-Javadoc) + * @see java.lang.Number#intValue() + */ + @Override + public int intValue() { + return get(); + } + + /* + * (non-Javadoc) + * @see java.lang.Number#longValue() + */ + @Override + public long longValue() { + return get(); + } + + /* + * (non-Javadoc) + * @see java.lang.Number#floatValue() + */ + @Override + public float floatValue() { + return get(); + } + + /* + * (non-Javadoc) + * @see java.lang.Number#doubleValue() + */ + @Override + public double doubleValue() { + return get(); } } diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java index 4b9f0452a..2659e408c 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java @@ -31,48 +31,50 @@ import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.serializer.GenericToStringSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** * Atomic long backed by Redis. Uses Redis atomic increment/decrement and watch/multi/exec operations for CAS * operations. * - * @see java.util.concurrent.atomic.AtomicLong * @author Costin Leau * @author Thomas Darimont * @author Christoph Strobl * @author Mark Paluch + * @see java.util.concurrent.atomic.AtomicLong */ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOperations { private static final long serialVersionUID = 1L; private volatile String key; - private ValueOperations operations; - private RedisOperations generalOps; + + private final ValueOperations operations; + private final RedisOperations generalOps; /** - * Constructs a new RedisAtomicLong instance. Uses the value existing in Redis or 0 if none is found. + * Constructs a new {@link RedisAtomicLong} instance. Uses the value existing in Redis or 0 if none is found. * - * @param redisCounter redis counter - * @param factory connection factory + * @param redisCounter Redis key of this counter. + * @param factory connection factory. */ public RedisAtomicLong(String redisCounter, RedisConnectionFactory factory) { this(redisCounter, factory, null); } /** - * Constructs a new RedisAtomicLong instance. + * Constructs a new {@link RedisAtomicLong} instance. * - * @param redisCounter - * @param factory - * @param initialValue + * @param redisCounter Redis key of this counter. + * @param factory connection factory. + * @param initialValue initial value to set if the Redis key is absent. */ public RedisAtomicLong(String redisCounter, RedisConnectionFactory factory, long initialValue) { this(redisCounter, factory, Long.valueOf(initialValue)); } - private RedisAtomicLong(String redisCounter, RedisConnectionFactory factory, Long initialValue) { + private RedisAtomicLong(String redisCounter, RedisConnectionFactory factory, @Nullable Long initialValue) { Assert.hasText(redisCounter, "a valid counter name is required"); Assert.notNull(factory, "a valid factory is required"); @@ -97,10 +99,10 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe } /** - * Constructs a new RedisAtomicLong instance. Uses the value existing in Redis or 0 if none is found. + * Constructs a new {@link RedisAtomicLong} instance. Uses the value existing in Redis or 0 if none is found. * - * @param redisCounter the redis counter - * @param template the template + * @param redisCounter Redis key of this counter. + * @param template the template. * @see #RedisAtomicLong(String, RedisConnectionFactory, long) */ public RedisAtomicLong(String redisCounter, RedisOperations template) { @@ -108,7 +110,7 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe } /** - * Constructs a new RedisAtomicLong instance. + * Constructs a new {@link RedisAtomicLong} instance. *

* Note: You need to configure the given {@code template} with appropriate {@link RedisSerializer} for the key and * value. The key serializer must be able to deserialize to a {@link String} and the value serializer must be able to @@ -118,15 +120,15 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe * which uses appropriate default serializers, in this case {@link StringRedisSerializer} for the key and * {@link GenericToStringSerializer} for the value. * - * @param redisCounter the redis counter + * @param redisCounter Redis key of this counter. * @param template the template - * @param initialValue the initial value + * @param initialValue initial value to set if the Redis key is absent. */ public RedisAtomicLong(String redisCounter, RedisOperations template, long initialValue) { this(redisCounter, template, Long.valueOf(initialValue)); } - private RedisAtomicLong(String redisCounter, RedisOperations template, Long initialValue) { + private RedisAtomicLong(String redisCounter, RedisOperations template, @Nullable Long initialValue) { Assert.hasText(redisCounter, "a valid counter name is required"); Assert.notNull(template, "a valid template is required"); @@ -149,7 +151,7 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe /** * Gets the current value. * - * @return the current value + * @return the current value. */ public long get() { @@ -173,29 +175,29 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe /** * Atomically sets to the given value and returns the old value. * - * @param newValue the new value - * @return the previous value + * @param newValue the new value. + * @return the previous value. */ public long getAndSet(long newValue) { Long value = operations.getAndSet(key, newValue); - if (value != null) { - return value.longValue(); - } - return 0; + return value != null ? value.longValue() : 0; } /** * Atomically sets the value to the given updated value if the current value {@code ==} the expected value. * - * @param expect the expected value - * @param update the new value - * @return true if successful. False return indicates that the actual value was not equal to the expected value. + * @param expect the expected value. + * @param update the new value. + * @return {@literal true} if successful. {@literal false} indicates that the actual value was not equal to the + * expected value. */ - public boolean compareAndSet(final long expect, final long update) { + public boolean compareAndSet(long expect, long update) { + return generalOps.execute(new SessionCallback() { + @Override @SuppressWarnings("unchecked") public Boolean execute(RedisOperations operations) { for (;;) { @@ -218,7 +220,7 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe /** * Atomically increments by one the current value. * - * @return the previous value + * @return the previous value. */ public long getAndIncrement() { return incrementAndGet() - 1; @@ -227,7 +229,7 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe /** * Atomically decrements by one the current value. * - * @return the previous value + * @return the previous value. */ public long getAndDecrement() { return decrementAndGet() + 1; @@ -236,8 +238,8 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe /** * Atomically adds the given value to the current value. * - * @param delta the value to add - * @return the previous value + * @param delta the value to add. + * @return the previous value. */ public long getAndAdd(final long delta) { return addAndGet(delta) - delta; @@ -246,7 +248,7 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe /** * Atomically increments by one the current value. * - * @return the updated value + * @return the updated value. */ public long incrementAndGet() { return operations.increment(key, 1); @@ -255,7 +257,7 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe /** * Atomically decrements by one the current value. * - * @return the updated value + * @return the updated value. */ public long decrementAndGet() { return operations.increment(key, -1); @@ -264,64 +266,119 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe /** * Atomically adds the given value to the current value. * - * @param delta the value to add - * @return the updated value + * @param delta the value to add. + * @return the updated value. */ public long addAndGet(long delta) { return operations.increment(key, delta); } /** - * Returns the String representation of the current value. - * * @return the String representation of the current value. */ + @Override public String toString() { return Long.toString(get()); } - public int intValue() { - return (int) get(); - } - - public long longValue() { - return get(); - } - - public float floatValue() { - return (float) get(); - } - - public double doubleValue() { - return (double) get(); - } - + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getKey() + */ + @Override public String getKey() { return key; } - public Boolean expire(long timeout, TimeUnit unit) { - return generalOps.expire(key, timeout, unit); - } - - public Boolean expireAt(Date date) { - return generalOps.expireAt(key, date); + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getType() + */ + @Override + public DataType getType() { + return DataType.STRING; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getExpire() + */ + @Override public Long getExpire() { return generalOps.getExpire(key); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expire(long, java.util.concurrent.TimeUnit) + */ + @Override + public Boolean expire(long timeout, TimeUnit unit) { + return generalOps.expire(key, timeout, unit); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expireAt(java.util.Date) + */ + @Override + public Boolean expireAt(Date date) { + return generalOps.expireAt(key, date); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#persist() + */ + @Override public Boolean persist() { return generalOps.persist(key); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#rename(java.lang.Object) + */ + @Override public void rename(String newKey) { + generalOps.rename(key, newKey); key = newKey; } - public DataType getType() { - return DataType.STRING; + /* + * (non-Javadoc) + * @see java.lang.Number#intValue() + */ + @Override + public int intValue() { + return (int) get(); + } + + /* + * (non-Javadoc) + * @see java.lang.Number#longValue() + */ + @Override + public long longValue() { + return get(); + } + + /* + * (non-Javadoc) + * @see java.lang.Number#floatValue() + */ + @Override + public float floatValue() { + return get(); + } + + /* + * (non-Javadoc) + * @see java.lang.Number#doubleValue() + */ + @Override + public double doubleValue() { + return get(); } } diff --git a/src/main/java/org/springframework/data/redis/support/atomic/package-info.java b/src/main/java/org/springframework/data/redis/support/atomic/package-info.java index ee64b49b2..f91d1502c 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/package-info.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/package-info.java @@ -2,4 +2,5 @@ * Small toolkit mirroring the {@code java.util.atomic} package in Redis. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.support.atomic; diff --git a/src/main/java/org/springframework/data/redis/support/collections/AbstractRedisCollection.java b/src/main/java/org/springframework/data/redis/support/collections/AbstractRedisCollection.java index 1d942c22f..3dcdf0385 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/AbstractRedisCollection.java +++ b/src/main/java/org/springframework/data/redis/support/collections/AbstractRedisCollection.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2014 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 - * + * * http://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. @@ -26,54 +26,94 @@ import org.springframework.lang.Nullable; /** * Base implementation for {@link RedisCollection}. Provides a skeletal implementation. Note that the collection support * works only with normal, non-pipeline/multi-exec connections as it requires a reply to be sent right away. - * + * * @author Costin Leau * @author Christoph Strobl + * @author Mark Paluch */ public abstract class AbstractRedisCollection extends AbstractCollection implements RedisCollection { public static final String ENCODING = "UTF-8"; private volatile String key; + private final RedisOperations operations; - public AbstractRedisCollection(String key, RedisOperations operations) { + /** + * Constructs a new {@link AbstractRedisCollection} instance. + * + * @param key Redis key of this collection. + * @param operations {@link RedisOperations} for the value type of this collection. + */ + public AbstractRedisCollection(String key, RedisOperations operations) { + this.key = key; this.operations = operations; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getKey() + */ + @Override public String getKey() { return key; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisStore#getOperations() + */ + @Override public RedisOperations getOperations() { return operations; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#addAll(java.util.Collection) + */ @Override public boolean addAll(Collection c) { + boolean modified = false; + for (E e : c) { modified |= add(e); } + return modified; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#containsAll(java.util.Collection) + */ @Override public boolean containsAll(Collection c) { + boolean contains = true; + for (Object object : c) { contains &= contains(object); } + return contains; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#removeAll(java.util.Collection) + */ @Override public boolean removeAll(Collection c) { + boolean modified = false; + for (Object object : c) { modified |= remove(object); } + return modified; } @@ -119,25 +159,35 @@ public abstract class AbstractRedisCollection extends AbstractCollection i */ @Override public void rename(final String newKey) { + if (!this.isEmpty()) { CollectionUtils.rename(key, newKey, operations); } + key = newKey; } protected void checkResult(@Nullable Object obj) { + if (obj == null) { throw new IllegalStateException("Cannot read collection with Redis connection in pipeline/multi-exec mode"); } } + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override public boolean equals(Object o) { + if (o == this) return true; if (o instanceof RedisStore) { return key.equals(((RedisStore) o).getKey()); } + if (o instanceof AbstractRedisCollection) { return o.hashCode() == hashCode(); } @@ -145,16 +195,31 @@ public abstract class AbstractRedisCollection extends AbstractCollection i return false; } + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override public int hashCode() { + int result = 17 + getClass().hashCode(); result = result * 31 + key.hashCode(); + return result; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#toString() + */ + @Override public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("RedisStore for key:"); sb.append(getKey()); + return sb.toString(); } diff --git a/src/main/java/org/springframework/data/redis/support/collections/CollectionUtils.java b/src/main/java/org/springframework/data/redis/support/collections/CollectionUtils.java index e8ae66b1c..0c9f32649 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/CollectionUtils.java +++ b/src/main/java/org/springframework/data/redis/support/collections/CollectionUtils.java @@ -70,33 +70,4 @@ abstract class CollectionUtils { } }); } - - static Boolean renameIfAbsent(final K key, final K newKey, RedisOperations operations) { - return operations.execute(new SessionCallback() { - @SuppressWarnings("unchecked") - public Boolean execute(RedisOperations operations) throws DataAccessException { - List exec = null; - do { - operations.watch(key); - - if (operations.hasKey(key)) { - operations.multi(); - operations.renameIfAbsent(key, newKey); - } else { - operations.watch(newKey); - operations.multi(); - operations.hasKey(newKey); - operations.hasKey(newKey); - } - exec = operations.exec(); - } while (exec == null); - - boolean result = ((Long) exec.get(0) == 1); - if (exec.size() > 1) { - result = !result; - } - return result; - } - }); - } } diff --git a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisList.java b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisList.java index da32533e7..1eb9cca4b 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisList.java +++ b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisList.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2017 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 - * + * * http://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. @@ -33,7 +33,7 @@ import org.springframework.lang.Nullable; * (LIFO ordering) and deques (or double ended queues). Allows the maximum size (or the cap) to be specified to prevent * the list from over growing. Note that all write operations will execute immediately, whether a cap is specified or * not - the list will always accept new items (trimming the tail after each insert in case of capped collections). - * + * * @author Costin Leau * @author Christoph Strobl */ @@ -42,7 +42,6 @@ public class DefaultRedisList extends AbstractRedisCollection implements R private final BoundListOperations listOps; private volatile int maxSize = 0; - private volatile boolean capped = false; private class DefaultRedisListIterator extends RedisIterator { @@ -51,98 +50,132 @@ public class DefaultRedisList extends AbstractRedisCollection implements R super(delegate); } + @Override protected void removeFromRedisStorage(E item) { DefaultRedisList.this.remove(item); } } /** - * Constructs a new, uncapped DefaultRedisList instance. - * - * @param key - * @param operations + * Constructs a new, uncapped {@link DefaultRedisList} instance. + * + * @param key Redis key of this list. + * @param operations {@link RedisOperations} for the value type of this list. */ public DefaultRedisList(String key, RedisOperations operations) { this(operations.boundListOps(key)); } /** - * Constructs a new, uncapped DefaultRedisList instance. - * - * @param boundOps + * Constructs a new, uncapped {@link DefaultRedisList} instance. + * + * @param boundOps {@link BoundListOperations} for the value type of this list. */ public DefaultRedisList(BoundListOperations boundOps) { this(boundOps, 0); } /** - * Constructs a new DefaultRedisList instance. - * - * @param boundOps + * Constructs a new {@link DefaultRedisList} instance. + * + * @param boundOps {@link BoundListOperations} for the value type of this list. * @param maxSize */ public DefaultRedisList(BoundListOperations boundOps, int maxSize) { + super(boundOps.getKey(), boundOps.getOperations()); + listOps = boundOps; setMaxSize(maxSize); } /** * Sets the maximum size of the (capped) list. A value of 0 means unlimited. - * + * * @param maxSize list maximum size */ public void setMaxSize(int maxSize) { + this.maxSize = maxSize; capped = (maxSize > 0); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisList#range(long, long) + */ + @Override public List range(long start, long end) { return listOps.range(start, end); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisList#trim(int, int) + */ + @Override public RedisList trim(int start, int end) { listOps.trim(start, end); return this; } - private List content() { - return listOps.range(0, -1); - } - - private void cap() { - if (capped) { - listOps.trim(0, maxSize - 1); - } - } - + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#iterator() + */ + @Override public Iterator iterator() { List list = content(); checkResult(list); return new DefaultRedisListIterator(list.iterator()); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#size() + */ + @Override public int size() { Long size = listOps.size(); checkResult(size); return size.intValue(); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#add(java.lang.Object) + */ + @Override public boolean add(E value) { listOps.rightPush(value); cap(); return true; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#clear() + */ + @Override public void clear() { listOps.trim(size() + 1, 0); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#remove(java.lang.Object) + */ + @Override public boolean remove(Object o) { Long result = listOps.remove(1, o); return (result != null && result.longValue() > 0); } + /* + * (non-Javadoc) + * @see java.util.List#add(int, java.lang.Object) + */ + @Override public void add(int index, E element) { if (index == 0) { listOps.leftPush(element); @@ -165,6 +198,11 @@ public class DefaultRedisList extends AbstractRedisCollection implements R throw new IllegalArgumentException("Redis supports insertion only at the beginning or the end of the list"); } + /* + * (non-Javadoc) + * @see java.util.List#addAll(int, java.util.Collection) + */ + @Override public boolean addAll(int index, Collection c) { // insert collection in reverse if (index == 0) { @@ -194,6 +232,11 @@ public class DefaultRedisList extends AbstractRedisCollection implements R throw new IllegalArgumentException("Redis supports insertion only at the beginning or the end of the list"); } + /* + * (non-Javadoc) + * @see java.util.List#get(int) + */ + @Override public E get(int index) { if (index < 0 || index > size()) { throw new IndexOutOfBoundsException(); @@ -201,26 +244,56 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return listOps.index(index); } + /* + * (non-Javadoc) + * @see java.util.List#indexOf(java.lang.Object) + */ + @Override public int indexOf(Object o) { throw new UnsupportedOperationException(); } + /* + * (non-Javadoc) + * @see java.util.List#lastIndexOf(java.lang.Object) + */ + @Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); } + /* + * (non-Javadoc) + * @see java.util.List#listIterator() + */ + @Override public ListIterator listIterator() { throw new UnsupportedOperationException(); } + /* + * (non-Javadoc) + * @see java.util.List#listIterator(int) + */ + @Override public ListIterator listIterator(int index) { throw new UnsupportedOperationException(); } + /* + * (non-Javadoc) + * @see java.util.List#remove(int) + */ + @Override public E remove(int index) { throw new UnsupportedOperationException(); } + /* + * (non-Javadoc) + * @see java.util.List#set(int, java.lang.Object) + */ + @Override public E set(int index, E e) { E object = get(index); @@ -228,6 +301,11 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return object; } + /* + * (non-Javadoc) + * @see java.util.List#subList(int, int) + */ + @Override public List subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); } @@ -236,6 +314,11 @@ public class DefaultRedisList extends AbstractRedisCollection implements R // Queue methods // + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#element() + */ + @Override public E element() { E value = peek(); if (value == null) { @@ -245,22 +328,42 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return value; } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#offer(java.lang.Object) + */ + @Override public boolean offer(E e) { listOps.rightPush(e); cap(); return true; } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#peek() + */ + @Override @Nullable public E peek() { return listOps.index(0); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#poll() + */ + @Override @Nullable public E poll() { return listOps.leftPop(); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#remove() + */ + @Override public E remove() { E value = poll(); @@ -275,25 +378,50 @@ public class DefaultRedisList extends AbstractRedisCollection implements R // Dequeue // + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#addFirst(java.lang.Object) + */ + @Override public void addFirst(E e) { listOps.leftPush(e); cap(); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#addLast(java.lang.Object) + */ + @Override public void addLast(E e) { add(e); } + /* + * (non-Javadoc) + * @see java.util.Deque#descendingIterator() + */ + @Override public Iterator descendingIterator() { List content = content(); Collections.reverse(content); return new DefaultRedisListIterator(content.iterator()); } + /* + * (non-Javadoc) + * @see java.util.Deque#getFirst() + */ + @Override public E getFirst() { return element(); } + /* + * (non-Javadoc) + * @see java.util.Deque#getLast() + */ + @Override public E getLast() { E e = peekLast(); if (e == null) { @@ -302,36 +430,71 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return e; } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#offerFirst(java.lang.Object) + */ + @Override public boolean offerFirst(E e) { addFirst(e); return true; } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#offerLast(java.lang.Object) + */ + @Override public boolean offerLast(E e) { addLast(e); return true; } + /* + * (non-Javadoc) + * @see java.util.Deque#peekFirst() + */ + @Override @Nullable public E peekFirst() { return peek(); } + /* + * (non-Javadoc) + * @see java.util.Deque#peekLast() + */ + @Override @Nullable public E peekLast() { return listOps.index(-1); } + /* + * (non-Javadoc) + * @see java.util.Deque#pollFirst() + */ + @Override @Nullable public E pollFirst() { return poll(); } + /* + * (non-Javadoc) + * @see java.util.Deque#pollLast() + */ + @Override @Nullable public E pollLast() { return listOps.rightPop(); } + /* + * (non-Javadoc) + * @see java.util.Deque#pop() + */ + @Override public E pop() { E e = poll(); @@ -341,18 +504,38 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return e; } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#push(java.lang.Object) + */ + @Override public void push(E e) { addFirst(e); } + /* + * (non-Javadoc) + * @see java.util.Deque#removeFirst() + */ + @Override public E removeFirst() { return pop(); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#removeFirstOccurrence(java.lang.Object) + */ + @Override public boolean removeFirstOccurrence(Object o) { return remove(o); } + /* + * (non-Javadoc) + * @see java.util.Deque#removeLast() + */ + @Override public E removeLast() { E e = pollLast(); if (e == null) { @@ -361,6 +544,11 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return e; } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#removeLastOccurrence(java.lang.Object) + */ + @Override public boolean removeLastOccurrence(Object o) { Long result = listOps.remove(-1, o); return (result != null && result.longValue() > 0); @@ -369,6 +557,11 @@ public class DefaultRedisList extends AbstractRedisCollection implements R // // BlockingQueue // + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingQueue#drainTo(java.util.Collection, int) + */ + @Override public int drainTo(Collection c, int maxElements) { if (this.equals(c)) { throw new IllegalArgumentException("Cannot drain a queue to itself"); @@ -384,28 +577,57 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return loop; } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingQueue#drainTo(java.util.Collection) + */ + @Override public int drainTo(Collection c) { return drainTo(c, size()); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#offer(java.lang.Object, long, java.util.concurrent.TimeUnit) + */ + @Override public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { return offer(e); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#poll(long, java.util.concurrent.TimeUnit) + */ + @Override @Nullable public E poll(long timeout, TimeUnit unit) throws InterruptedException { - E element = listOps.leftPop(timeout, unit); - return (element == null ? null : element); + return listOps.leftPop(timeout, unit); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#put(java.lang.Object) + */ + @Override public void put(E e) throws InterruptedException { offer(e); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingQueue#remainingCapacity() + */ + @Override public int remainingCapacity() { return Integer.MAX_VALUE; } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#take() + */ + @Override @Nullable public E take() throws InterruptedException { return poll(0, TimeUnit.SECONDS); @@ -415,44 +637,98 @@ public class DefaultRedisList extends AbstractRedisCollection implements R // BlockingDeque // + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#offerFirst(java.lang.Object, long, java.util.concurrent.TimeUnit) + */ + @Override public boolean offerFirst(E e, long timeout, TimeUnit unit) throws InterruptedException { return offerFirst(e); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#offerLast(java.lang.Object, long, java.util.concurrent.TimeUnit) + */ + @Override public boolean offerLast(E e, long timeout, TimeUnit unit) throws InterruptedException { return offerLast(e); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#pollFirst(long, java.util.concurrent.TimeUnit) + */ + @Override @Nullable public E pollFirst(long timeout, TimeUnit unit) throws InterruptedException { return poll(timeout, unit); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#pollLast(long, java.util.concurrent.TimeUnit) + */ + @Override @Nullable public E pollLast(long timeout, TimeUnit unit) throws InterruptedException { - E element = listOps.rightPop(timeout, unit); - return (element == null ? null : element); + return listOps.rightPop(timeout, unit); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#putFirst(java.lang.Object) + */ + @Override public void putFirst(E e) throws InterruptedException { add(e); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#putLast(java.lang.Object) + */ + @Override public void putLast(E e) throws InterruptedException { put(e); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#takeFirst() + */ + @Override @Nullable public E takeFirst() throws InterruptedException { return take(); } + /* + * (non-Javadoc) + * @see java.util.concurrent.BlockingDeque#takeLast() + */ + @Override @Nullable public E takeLast() throws InterruptedException { return pollLast(0, TimeUnit.SECONDS); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getType() + */ + @Override public DataType getType() { return DataType.LIST; } + + private List content() { + return listOps.range(0, -1); + } + + private void cap() { + if (capped) { + listOps.trim(0, maxSize - 1); + } + } } diff --git a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisMap.java b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisMap.java index e89a7ba96..9e563e2bd 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisMap.java +++ b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisMap.java @@ -45,8 +45,8 @@ public class DefaultRedisMap implements RedisMap { private class DefaultRedisMapEntry implements Map.Entry { - private K key; - private @Nullable V value; + private final K key; + private @Nullable final V value; public DefaultRedisMapEntry(K key, @Nullable V value) { @@ -54,66 +54,108 @@ public class DefaultRedisMap implements RedisMap { this.value = value; } + @Override public K getKey() { return key; } + @Override @Nullable public V getValue() { return value; } + @Override public V setValue(@Nullable V value) { throw new UnsupportedOperationException(); } } /** - * Constructs a new DefaultRedisMap instance. + * Constructs a new {@link DefaultRedisMap} instance. * - * @param key - * @param operations + * @param key Redis key of this map. + * @param operations {@link RedisOperations} for this map. + * @see RedisOperations#getHashKeySerializer() + * @see RedisOperations#getValueSerializer() */ public DefaultRedisMap(String key, RedisOperations operations) { this.hashOps = operations.boundHashOps(key); } /** - * Constructs a new DefaultRedisMap instance. + * Constructs a new {@link DefaultRedisMap} instance. * - * @param boundOps + * @param boundOps {@link BoundHashOperations} for this map. */ public DefaultRedisMap(BoundHashOperations boundOps) { this.hashOps = boundOps; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisMap#increment(java.lang.Object, long) + */ + @Override public Long increment(K key, long delta) { return hashOps.increment(key, delta); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisMap#increment(java.lang.Object, double) + */ + @Override public Double increment(K key, double delta) { return hashOps.increment(key, delta); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisStore#getOperations() + */ + @Override public RedisOperations getOperations() { return hashOps.getOperations(); } + /* + * (non-Javadoc) + * @see java.util.Map#clear() + */ + @Override public void clear() { getOperations().delete(Collections.singleton(getKey())); } + /* + * (non-Javadoc) + * @see java.util.Map#containsKey(java.lang.Object) + */ + @Override public boolean containsKey(Object key) { + Boolean result = hashOps.hasKey(key); checkResult(result); return result; } + /* + * (non-Javadoc) + * @see java.util.Map#containsValue(java.lang.Object) + */ + @Override public boolean containsValue(Object value) { throw new UnsupportedOperationException(); } + /* + * (non-Javadoc) + * @see java.util.Map#entrySet() + */ + @Override public Set> entrySet() { + Set keySet = keySet(); checkResult(keySet); Collection multiGet = hashOps.multiGet(keySet); @@ -129,47 +171,96 @@ public class DefaultRedisMap implements RedisMap { return entries; } + /* + * (non-Javadoc) + * @see java.util.Map#get(java.lang.Object) + */ + @Override @Nullable public V get(Object key) { return hashOps.get(key); } + /* + * (non-Javadoc) + * @see java.util.Map#isEmpty() + */ + @Override public boolean isEmpty() { return size() == 0; } + /* + * (non-Javadoc) + * @see java.util.Map#keySet() + */ + @Override public Set keySet() { return hashOps.keys(); } + /* + * (non-Javadoc) + * @see java.util.Map#put(java.lang.Object, java.lang.Object) + */ + @Override public V put(K key, V value) { + V oldV = get(key); hashOps.put(key, value); return oldV; } + /* + * (non-Javadoc) + * @see java.util.Map#putAll(java.util.Map) + */ + @Override public void putAll(Map m) { hashOps.putAll(m); } + /* + * (non-Javadoc) + * @see java.util.Map#remove(java.lang.Object) + */ + @Override @Nullable public V remove(Object key) { + V v = get(key); hashOps.delete(key); return v; } + /* + * (non-Javadoc) + * @see java.util.Map#size() + */ + @Override public int size() { + Long size = hashOps.size(); checkResult(size); return size.intValue(); } + /* + * (non-Javadoc) + * @see java.util.Map#values() + */ + @Override public Collection values() { return hashOps.values(); } + /* + * (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override public boolean equals(Object o) { + if (o == this) return true; @@ -179,29 +270,54 @@ public class DefaultRedisMap implements RedisMap { return false; } + /* + * (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override public int hashCode() { + int result = 17 + getClass().hashCode(); result = result * 31 + getKey().hashCode(); return result; } + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override public String toString() { + StringBuilder sb = new StringBuilder(); sb.append("RedisStore for key:"); sb.append(getKey()); return sb.toString(); } + /* + * (non-Javadoc) + * @see java.util.concurrent.ConcurrentMap#putIfAbsent(java.lang.Object, java.lang.Object) + */ + @Override @Nullable public V putIfAbsent(K key, V value) { return (hashOps.putIfAbsent(key, value) ? null : get(key)); } - public boolean remove(final Object key, final Object value) { + /* + * (non-Javadoc) + * @see java.util.concurrent.ConcurrentMap#remove(java.lang.Object, java.lang.Object) + */ + @Override + public boolean remove(Object key, Object value) { + if (value == null) { throw new NullPointerException(); } + return hashOps.getOperations().execute(new SessionCallback() { + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public Boolean execute(RedisOperations ops) { for (;;) { @@ -221,11 +337,19 @@ public class DefaultRedisMap implements RedisMap { }); } - public boolean replace(final K key, V oldValue, V newValue) { + /* + * (non-Javadoc) + * @see java.util.concurrent.ConcurrentMap#replace(java.lang.Object, java.lang.Object, java.lang.Object) + */ + @Override + public boolean replace(K key, V oldValue, V newValue) { + if (oldValue == null || newValue == null) { throw new NullPointerException(); } + return hashOps.getOperations().execute(new SessionCallback() { + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public Boolean execute(RedisOperations ops) { for (;;) { @@ -245,12 +369,20 @@ public class DefaultRedisMap implements RedisMap { }); } + /* + * (non-Javadoc) + * @see java.util.concurrent.ConcurrentMap#replace(java.lang.Object, java.lang.Object) + */ + @Override @Nullable - public V replace(final K key, final V value) { + public V replace(K key, V value) { + if (value == null) { throw new NullPointerException(); } + return hashOps.getOperations().execute(new SessionCallback() { + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public V execute(RedisOperations ops) { for (;;) { @@ -270,30 +402,65 @@ public class DefaultRedisMap implements RedisMap { }); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expire(long, java.util.concurrent.TimeUnit) + */ + @Override public Boolean expire(long timeout, TimeUnit unit) { return hashOps.expire(timeout, unit); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expireAt(java.util.Date) + */ + @Override public Boolean expireAt(Date date) { return hashOps.expireAt(date); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getExpire() + */ + @Override public Long getExpire() { return hashOps.getExpire(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#persist() + */ + @Override public Boolean persist() { return hashOps.persist(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getKey() + */ + @Override public String getKey() { return hashOps.getKey(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#rename(java.lang.Object) + */ + @Override public void rename(String newKey) { hashOps.rename(newKey); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getType() + */ + @Override public DataType getType() { return hashOps.getType(); } diff --git a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisSet.java b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisSet.java index 7fb0b6ede..ee1ca0481 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisSet.java +++ b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisSet.java @@ -44,86 +44,154 @@ public class DefaultRedisSet extends AbstractRedisCollection implements Re super(delegate); } + @Override protected void removeFromRedisStorage(E item) { DefaultRedisSet.this.remove(item); } } /** - * Constructs a new DefaultRedisSet instance. + * Constructs a new {@link DefaultRedisSet} instance. * - * @param key - * @param operations + * @param key Redis key of this set. + * @param operations {@link RedisOperations} for the value type of this set. */ public DefaultRedisSet(String key, RedisOperations operations) { + super(key, operations); boundSetOps = operations.boundSetOps(key); } /** - * Constructs a new DefaultRedisSet instance. + * Constructs a new {@link DefaultRedisSet} instance. * - * @param boundOps + * @param boundOps {@link BoundSetOperations} for the value type of this set. */ public DefaultRedisSet(BoundSetOperations boundOps) { + super(boundOps.getKey(), boundOps.getOperations()); this.boundSetOps = boundOps; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#diff(org.springframework.data.redis.support.collections.RedisSet) + */ + @Override public Set diff(RedisSet set) { return boundSetOps.diff(set.getKey()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#diff(java.util.Collection) + */ + @Override public Set diff(Collection> sets) { return boundSetOps.diff(CollectionUtils.extractKeys(sets)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#diffAndStore(org.springframework.data.redis.support.collections.RedisSet, java.lang.String) + */ + @Override public RedisSet diffAndStore(RedisSet set, String destKey) { boundSetOps.diffAndStore(set.getKey(), destKey); return new DefaultRedisSet<>(boundSetOps.getOperations().boundSetOps(destKey)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#diffAndStore(java.util.Collection, java.lang.String) + */ + @Override public RedisSet diffAndStore(Collection> sets, String destKey) { boundSetOps.diffAndStore(CollectionUtils.extractKeys(sets), destKey); return new DefaultRedisSet<>(boundSetOps.getOperations().boundSetOps(destKey)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#intersect(org.springframework.data.redis.support.collections.RedisSet) + */ + @Override public Set intersect(RedisSet set) { return boundSetOps.intersect(set.getKey()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#intersect(java.util.Collection) + */ + @Override public Set intersect(Collection> sets) { return boundSetOps.intersect(CollectionUtils.extractKeys(sets)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#intersectAndStore(org.springframework.data.redis.support.collections.RedisSet, java.lang.String) + */ + @Override public RedisSet intersectAndStore(RedisSet set, String destKey) { boundSetOps.intersectAndStore(set.getKey(), destKey); return new DefaultRedisSet<>(boundSetOps.getOperations().boundSetOps(destKey)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#intersectAndStore(java.util.Collection, java.lang.String) + */ + @Override public RedisSet intersectAndStore(Collection> sets, String destKey) { boundSetOps.intersectAndStore(CollectionUtils.extractKeys(sets), destKey); return new DefaultRedisSet<>(boundSetOps.getOperations().boundSetOps(destKey)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#union(org.springframework.data.redis.support.collections.RedisSet) + */ + @Override public Set union(RedisSet set) { return boundSetOps.union(set.getKey()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#union(java.util.Collection) + */ + @Override public Set union(Collection> sets) { return boundSetOps.union(CollectionUtils.extractKeys(sets)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#unionAndStore(org.springframework.data.redis.support.collections.RedisSet, java.lang.String) + */ + @Override public RedisSet unionAndStore(RedisSet set, String destKey) { boundSetOps.unionAndStore(set.getKey(), destKey); return new DefaultRedisSet<>(boundSetOps.getOperations().boundSetOps(destKey)); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#unionAndStore(java.util.Collection, java.lang.String) + */ + @Override public RedisSet unionAndStore(Collection> sets, String destKey) { boundSetOps.unionAndStore(CollectionUtils.extractKeys(sets), destKey); return new DefaultRedisSet<>(boundSetOps.getOperations().boundSetOps(destKey)); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#add(java.lang.Object) + */ + @Override @SuppressWarnings("unchecked") public boolean add(E e) { Long result = boundSetOps.add(e); @@ -131,6 +199,11 @@ public class DefaultRedisSet extends AbstractRedisCollection implements Re return result == 1; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#clear() + */ + @Override public void clear() { // intersect the set with a non existing one // TODO: find a safer way to clean the set @@ -138,34 +211,63 @@ public class DefaultRedisSet extends AbstractRedisCollection implements Re boundSetOps.intersectAndStore(Collections.singleton(randomKey), getKey()); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#contains(java.lang.Object) + */ + @Override public boolean contains(Object o) { Boolean result = boundSetOps.isMember(o); checkResult(result); return result; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#iterator() + */ + @Override public Iterator iterator() { Set members = boundSetOps.members(); checkResult(members); return new DefaultRedisSetIterator(members.iterator()); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#remove(java.lang.Object) + */ + @Override public boolean remove(Object o) { Long result = boundSetOps.remove(o); checkResult(result); return result == 1; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#size() + */ + @Override public int size() { Long result = boundSetOps.size(); checkResult(result); return result.intValue(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getType() + */ + @Override public DataType getType() { return DataType.SET; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisSet#scan() + */ /* * (non-Javadoc) * @see org.springframework.data.redis.support.collections.RedisSet#scan() 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 59335c227..3b1db8a6f 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 @@ -49,69 +49,96 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R super(delegate); } + @Override protected void removeFromRedisStorage(E item) { DefaultRedisZSet.this.remove(item); } } /** - * Constructs a new DefaultRedisZSet instance with a default score of '1'. + * Constructs a new {@link DefaultRedisZSet} instance with a default score of {@literal 1}. * - * @param key - * @param operations + * @param key Redis key of this set. + * @param operations {@link RedisOperations} for the value type of this set. */ public DefaultRedisZSet(String key, RedisOperations operations) { this(key, operations, 1); } /** - * Constructs a new DefaultRedisSortedSet instance. + * Constructs a new {@link DefaultRedisZSet} instance. * - * @param key - * @param operations + * @param key Redis key of this set. + * @param operations {@link RedisOperations} for the value type of this set. * @param defaultScore */ public DefaultRedisZSet(String key, RedisOperations operations, double defaultScore) { + super(key, operations); + boundZSetOps = operations.boundZSetOps(key); this.defaultScore = defaultScore; } /** - * Constructs a new DefaultRedisZSet instance with a default score of '1'. + * Constructs a new {@link DefaultRedisZSet} instance with a default score of '1'. * - * @param boundOps + * @param boundOps {@link BoundZSetOperations} for the value type of this set. */ public DefaultRedisZSet(BoundZSetOperations boundOps) { this(boundOps, 1); } /** - * Constructs a new DefaultRedisZSet instance. + * Constructs a new {@link DefaultRedisZSet} instance. * - * @param boundOps + * @param boundOps {@link BoundZSetOperations} for the value type of this set. * @param defaultScore */ public DefaultRedisZSet(BoundZSetOperations boundOps, double defaultScore) { + super(boundOps.getKey(), boundOps.getOperations()); + this.boundZSetOps = boundOps; this.defaultScore = defaultScore; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#intersectAndStore(org.springframework.data.redis.support.collections.RedisZSet, java.lang.String) + */ + @Override public RedisZSet intersectAndStore(RedisZSet set, String destKey) { + boundZSetOps.intersectAndStore(set.getKey(), destKey); return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#intersectAndStore(java.util.Collection, java.lang.String) + */ + @Override public RedisZSet intersectAndStore(Collection> sets, String destKey) { + boundZSetOps.intersectAndStore(CollectionUtils.extractKeys(sets), destKey); return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#range(long, long) + */ + @Override public Set range(long start, long end) { return boundZSetOps.range(start, end); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#reverseRange(long, long) + */ + @Override public Set reverseRange(long start, long end) { return boundZSetOps.reverseRange(start, end); } @@ -134,93 +161,191 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R return boundZSetOps.rangeByLex(range, limit); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#rangeByScore(double, double) + */ + @Override public Set rangeByScore(double min, double max) { return boundZSetOps.rangeByScore(min, max); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#reverseRangeByScore(double, double) + */ + @Override public Set reverseRangeByScore(double min, double max) { return boundZSetOps.reverseRangeByScore(min, max); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#rangeByScoreWithScores(double, double) + */ + @Override public Set> rangeByScoreWithScores(double min, double max) { return boundZSetOps.rangeByScoreWithScores(min, max); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#rangeWithScores(long, long) + */ + @Override public Set> rangeWithScores(long start, long end) { return boundZSetOps.rangeWithScores(start, end); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#reverseRangeByScoreWithScores(double, double) + */ + @Override public Set> reverseRangeByScoreWithScores(double min, double max) { return boundZSetOps.reverseRangeByScoreWithScores(min, max); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#reverseRangeWithScores(long, long) + */ + @Override public Set> reverseRangeWithScores(long start, long end) { return boundZSetOps.reverseRangeWithScores(start, end); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#remove(long, long) + */ + @Override public RedisZSet remove(long start, long end) { boundZSetOps.removeRange(start, end); return this; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#removeByScore(double, double) + */ + @Override public RedisZSet removeByScore(double min, double max) { boundZSetOps.removeRangeByScore(min, max); return this; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#unionAndStore(org.springframework.data.redis.support.collections.RedisZSet, java.lang.String) + */ + @Override public RedisZSet unionAndStore(RedisZSet set, String destKey) { boundZSetOps.unionAndStore(set.getKey(), destKey); return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#unionAndStore(java.util.Collection, java.lang.String) + */ + @Override public RedisZSet unionAndStore(Collection> sets, String destKey) { boundZSetOps.unionAndStore(CollectionUtils.extractKeys(sets), destKey); return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#add(java.lang.Object) + */ + @Override public boolean add(E e) { Boolean result = add(e, getDefaultScore()); checkResult(result); return result; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#add(java.lang.Object, double) + */ + @Override public boolean add(E e, double score) { Boolean result = boundZSetOps.add(e, score); checkResult(result); return result; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#clear() + */ + @Override public void clear() { boundZSetOps.removeRange(0, -1); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#contains(java.lang.Object) + */ + @Override public boolean contains(Object o) { return (boundZSetOps.rank(o) != null); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#iterator() + */ + @Override public Iterator iterator() { Set members = boundZSetOps.range(0, -1); checkResult(members); return new DefaultRedisSortedSetIterator(members.iterator()); } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#remove(java.lang.Object) + */ + @Override public boolean remove(Object o) { + Long result = boundZSetOps.remove(o); checkResult(result); return result == 1; } + /* + * (non-Javadoc) + * @see java.util.AbstractCollection#size() + */ + @Override public int size() { + Long result = boundZSetOps.size(); checkResult(result); return result.intValue(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#getDefaultScore() + */ + @Override public Double getDefaultScore() { return defaultScore; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#first() + */ + @Override public E first() { + Set members = boundZSetOps.range(0, 0); checkResult(members); Iterator iterator = members.iterator(); @@ -228,31 +353,59 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R if (iterator.hasNext()) { return iterator.next(); } + throw new NoSuchElementException(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#last() + */ + @Override public E last() { + Set members = boundZSetOps.reverseRange(0, 0); checkResult(members); Iterator iterator = members.iterator(); if (iterator.hasNext()) { return iterator.next(); } + throw new NoSuchElementException(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#rank(java.lang.Object) + */ + @Override public Long rank(Object o) { return boundZSetOps.rank(o); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#reverseRank(java.lang.Object) + */ + @Override public Long reverseRank(Object o) { return boundZSetOps.reverseRank(o); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#score(java.lang.Object) + */ + @Override public Double score(Object o) { return boundZSetOps.score(o); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getType() + */ + @Override public DataType getType() { return DataType.ZSET; } @@ -274,5 +427,4 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R public Cursor> scan(ScanOptions options) { return boundZSetOps.scan(options); } - } diff --git a/src/main/java/org/springframework/data/redis/support/collections/RedisProperties.java b/src/main/java/org/springframework/data/redis/support/collections/RedisProperties.java index af7d56806..bb095f220 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/RedisProperties.java +++ b/src/main/java/org/springframework/data/redis/support/collections/RedisProperties.java @@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.core.BoundHashOperations; import org.springframework.data.redis.core.RedisOperations; +import org.springframework.lang.Nullable; /** * {@link Properties} extension for a Redis back-store. Useful for reading (and storing) properties inside a Redis hash. @@ -50,58 +51,84 @@ public class RedisProperties extends Properties implements RedisMap delegate; /** - * Constructs a new RedisProperties instance. + * Constructs a new {@link RedisProperties} instance. */ public RedisProperties(BoundHashOperations boundOps) { this(null, boundOps); } /** - * Constructs a new RedisProperties instance. + * Constructs a new {@link RedisProperties} instance. * - * @param key - * @param operations + * @param key Redis key of this property map. + * @param operations {@link RedisOperations} for this properties. + * @see RedisOperations#getHashKeySerializer() + * @see RedisOperations#getHashValueSerializer() */ public RedisProperties(String key, RedisOperations operations) { this(null, operations. boundHashOps(key)); } /** - * Constructs a new RedisProperties instance. + * Constructs a new {@link RedisProperties} instance. * - * @param defaults - * @param boundOps + * @param defaults default properties to apply, can be {@literal null}. + * @param boundOps {@link BoundHashOperations} for this properties. */ - public RedisProperties(Properties defaults, BoundHashOperations boundOps) { + public RedisProperties(@Nullable Properties defaults, BoundHashOperations boundOps) { + super(defaults); + this.hashOps = boundOps; this.delegate = new DefaultRedisMap<>(boundOps); } /** - * Constructs a new RedisProperties instance. + * Constructs a new {@link RedisProperties} instance. * - * @param defaults - * @param key - * @param operations + * @param defaults default properties to apply, can be {@literal null}. + * @param key Redis key of this property map. + * @param operations {@link RedisOperations} for this properties. + * @see RedisOperations#getHashKeySerializer() + * @see RedisOperations#getHashValueSerializer() */ public RedisProperties(Properties defaults, String key, RedisOperations operations) { - this(defaults, operations. boundHashOps(key)); + this(defaults, operations.boundHashOps(key)); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#get(java.lang.Object) + */ + @Override public synchronized Object get(Object key) { return delegate.get(key); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object) + */ + @Override public synchronized Object put(Object key, Object value) { return delegate.put((String) key, (String) value); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#putAll(java.util.Map) + */ + @Override @SuppressWarnings("unchecked") public synchronized void putAll(Map t) { delegate.putAll((Map) t); } + /* + * (non-Javadoc) + * @see java.util.Properties#propertyNames() + */ + @Override public Enumeration propertyNames() { Set keys = new LinkedHashSet<>(delegate.keySet()); if (defaults != null) { @@ -110,39 +137,78 @@ public class RedisProperties extends Properties implements RedisMap elements() { - Collection values = delegate.values(); - return Collections.enumeration(values); + return Collections.enumeration((Collection) delegate.values()); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#entrySet() + */ + @Override @SuppressWarnings("unchecked") public Set> entrySet() { - Set entries = delegate.entrySet(); - return entries; + return (Set) delegate.entrySet(); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#equals(java.lang.Object) + */ + @Override public synchronized boolean equals(Object o) { + if (o == this) return true; @@ -152,104 +218,222 @@ public class RedisProperties extends Properties implements RedisMap keys() { Set keys = keySet(); return Collections.enumeration(keys); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#keySet() + */ + @Override @SuppressWarnings("unchecked") public Set keySet() { - Set keys = delegate.keySet(); - return keys; + return (Set) delegate.keySet(); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#remove(java.lang.Object) + */ + @Override public synchronized Object remove(Object key) { return delegate.remove(key); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#size() + */ + @Override public synchronized int size() { return delegate.size(); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#values() + */ + @Override @SuppressWarnings("unchecked") public Collection values() { - Collection vals = delegate.values(); - return vals; + return (Collection) delegate.values(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisMap#increment(java.lang.Object, long) + */ + @Override public Long increment(Object key, long delta) { return hashOps.increment((String) key, delta); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisMap#increment(java.lang.Object, double) + */ + @Override public Double increment(Object key, double delta) { return hashOps.increment((String) key, delta); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisStore#getOperations() + */ + @Override public RedisOperations getOperations() { return hashOps.getOperations(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expire(long, java.util.concurrent.TimeUnit) + */ + @Override public Boolean expire(long timeout, TimeUnit unit) { return hashOps.expire(timeout, unit); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#expireAt(java.util.Date) + */ + @Override public Boolean expireAt(Date date) { return hashOps.expireAt(date); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getExpire() + */ + @Override public Long getExpire() { return hashOps.getExpire(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getKey() + */ + @Override public String getKey() { return hashOps.getKey(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#getType() + */ + @Override public DataType getType() { return hashOps.getType(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#persist() + */ + @Override public Boolean persist() { return hashOps.persist(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.core.BoundKeyOperations#rename(java.lang.Object) + */ + @Override public void rename(String newKey) { hashOps.rename(newKey); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#putIfAbsent(java.lang.Object, java.lang.Object) + */ + @Override public Object putIfAbsent(Object key, Object value) { return (hashOps.putIfAbsent((String) key, (String) value) ? null : get(key)); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#remove(java.lang.Object, java.lang.Object) + */ + @Override public boolean remove(Object key, Object value) { return delegate.remove(key, value); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#replace(java.lang.Object, java.lang.Object, java.lang.Object) + */ + @Override public boolean replace(Object key, Object oldValue, Object newValue) { return delegate.replace((String) key, (String) oldValue, (String) newValue); } + /* + * (non-Javadoc) + * @see java.util.Hashtable#replace(java.lang.Object, java.lang.Object) + */ + @Override public Object replace(Object key, Object value) { return delegate.replace((String) key, (String) value); } + /* + * (non-Javadoc) + * @see java.util.Properties#storeToXML(java.io.OutputStream, java.lang.String, java.lang.String) + */ + @Override public synchronized void storeToXML(OutputStream os, String comment, String encoding) throws IOException { throw new UnsupportedOperationException(); } + /* + * (non-Javadoc) + * @see java.util.Properties#storeToXML(java.io.OutputStream, java.lang.String) + */ + @Override public synchronized void storeToXML(OutputStream os, String comment) throws IOException { throw new UnsupportedOperationException(); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisMap#scan() + */ @Override public Iterator> scan() { throw new UnsupportedOperationException(); diff --git a/src/main/java/org/springframework/data/redis/support/collections/package-info.java b/src/main/java/org/springframework/data/redis/support/collections/package-info.java index 946aef46f..deb156ae5 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/package-info.java +++ b/src/main/java/org/springframework/data/redis/support/collections/package-info.java @@ -12,4 +12,5 @@ * Map-like abstraction on top of a Redis hash. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.support.collections; diff --git a/src/main/java/org/springframework/data/redis/support/package-info.java b/src/main/java/org/springframework/data/redis/support/package-info.java index 22350f2a6..3f3f0541e 100644 --- a/src/main/java/org/springframework/data/redis/support/package-info.java +++ b/src/main/java/org/springframework/data/redis/support/package-info.java @@ -2,4 +2,5 @@ * Classes supporting the Redis packages, such as collection or atomic counters. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.support; diff --git a/src/main/java/org/springframework/data/redis/util/ByteUtils.java b/src/main/java/org/springframework/data/redis/util/ByteUtils.java index 3a718bed7..4d3ed2a4d 100644 --- a/src/main/java/org/springframework/data/redis/util/ByteUtils.java +++ b/src/main/java/org/springframework/data/redis/util/ByteUtils.java @@ -24,7 +24,7 @@ import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** - * Some handy methods for dealing with byte arrays. + * Some handy methods for dealing with {@code byte} arrays. * * @author Christoph Strobl * @author Mark Paluch @@ -34,30 +34,55 @@ public final class ByteUtils { private ByteUtils() {} - public static byte[] concat(byte[] arg1, byte[] arg2) { + /** + * Concatenate the given {@code byte} arrays into one, with overlapping array elements included twice. + *

+ * The order of elements in the original arrays is preserved. + * + * @param array1 the first array. + * @param array2 the second array. + * @return the new array. + */ + public static byte[] concat(byte[] array1, byte[] array2) { - byte[] result = Arrays.copyOf(arg1, arg1.length + arg2.length); - System.arraycopy(arg2, 0, result, arg1.length, arg2.length); + byte[] result = Arrays.copyOf(array1, array1.length + array2.length); + System.arraycopy(array2, 0, result, array1.length, array2.length); return result; } - public static byte[] concatAll(byte[]... args) { + /** + * Concatenate the given {@code byte} arrays into one, with overlapping array elements included twice. Returns a new, + * empty array if {@code arrays} was empty and returns the first array if {@code arrays} contains only a single array. + *

+ * The order of elements in the original arrays is preserved. + * + * @param arrays the arrays. + * @return the new array. + */ + public static byte[] concatAll(byte[]... arrays) { - if (args.length == 0) { + if (arrays.length == 0) { return new byte[] {}; } - if (args.length == 1) { - return args[0]; + if (arrays.length == 1) { + return arrays[0]; } - byte[] cur = concat(args[0], args[1]); - for (int i = 2; i < args.length; i++) { - cur = concat(cur, args[i]); + byte[] cur = concat(arrays[0], arrays[1]); + for (int i = 2; i < arrays.length; i++) { + cur = concat(cur, arrays[i]); } return cur; } + /** + * Split {@code source} into partitioned arrays using delimiter {@code c}. + * + * @param source the source array. + * @param c delimiter. + * @return the partitioned arrays. + */ public static byte[][] split(byte[] source, int c) { if (ObjectUtils.isEmpty(source)) { diff --git a/src/main/java/org/springframework/data/redis/util/package-info.java b/src/main/java/org/springframework/data/redis/util/package-info.java index 3c8b91f8d..2d87f277f 100644 --- a/src/main/java/org/springframework/data/redis/util/package-info.java +++ b/src/main/java/org/springframework/data/redis/util/package-info.java @@ -2,4 +2,5 @@ * Commonly used stuff for data manipulation throughout different driver specific implementations. */ @org.springframework.lang.NonNullApi +@org.springframework.lang.NonNullFields package org.springframework.data.redis.util; 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 5bf436bda..4d743e011 100644 --- a/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/RedisConnectionUnitTests.java @@ -436,8 +436,8 @@ public class RedisConnectionUnitTests { delegate.pSubscribe(listener, patterns); } - public void rename(byte[] oldName, byte[] newName) { - delegate.rename(oldName, newName); + public void rename(byte[] sourceKey, byte[] targetKey) { + delegate.rename(sourceKey, targetKey); } public boolean isPipelined() { @@ -464,8 +464,8 @@ public class RedisConnectionUnitTests { return delegate.sInter(keys); } - public Boolean renameNX(byte[] oldName, byte[] newName) { - return delegate.renameNX(oldName, newName); + public Boolean renameNX(byte[] sourceKey, byte[] targetKey) { + return delegate.renameNX(sourceKey, targetKey); } public Long zRank(byte[] key, byte[] value) { @@ -696,8 +696,8 @@ public class RedisConnectionUnitTests { return delegate.zRangeByScore(key, min, max, offset, count); } - public byte[] getRange(byte[] key, long begin, long end) { - return delegate.getRange(key, begin, end); + public byte[] getRange(byte[] key, long start, long end) { + return delegate.getRange(key, start, end); } public void setClientName(byte[] name) {