From 1b2e74c82f3c8b19a38b8d71abb29c70f6327bcd Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 13 Sep 2017 10:36:38 +0200 Subject: [PATCH] DATAREDIS-692 - Introduce usage of nullable annotations for API validation. Mark all packages with Spring Frameworks @NonNullApi. Add Spring's @Nullable to methods, parameters and fields that take or produce null values. Adapted using code to make sure the IDE can evaluate the null flow properly. Fix Javadoc in places where an invalid null handling policy was advertised. Strengthened null requirements for types that expose null-instances. Resolve some of the inherited null invariants, align Converters to null contract. Original pull request: #277. --- .../redis/ExceptionTranslationStrategy.java | 10 +- .../data/redis/VersionParser.java | 12 +- .../redis/cache/DefaultRedisCacheWriter.java | 20 +- .../data/redis/cache/RedisCache.java | 9 +- .../redis/cache/RedisCacheConfiguration.java | 5 +- .../data/redis/cache/RedisCacheManager.java | 3 +- .../data/redis/cache/RedisCacheWriter.java | 8 +- .../data/redis/cache/package-info.java | 5 +- .../redis/config/RedisCollectionParser.java | 1 + .../data/redis/config/package-info.java | 5 + .../connection/AbstractRedisConnection.java | 6 +- .../connection/ClusterCommandExecutor.java | 30 ++- .../data/redis/connection/ClusterInfo.java | 40 +++- .../ClusterNodeResourceProvider.java | 3 +- .../redis/connection/ClusterTopology.java | 7 +- .../connection/ClusterTopologyProvider.java | 6 +- .../data/redis/connection/DefaultMessage.java | 21 +- .../DefaultStringRedisConnection.java | 20 +- .../data/redis/connection/DefaultTuple.java | 14 +- .../connection/DefaultedRedisConnection.java | 5 +- .../data/redis/connection/FutureResult.java | 26 +- .../data/redis/connection/Message.java | 15 +- .../redis/connection/MessageListener.java | 15 +- .../data/redis/connection/NamedNode.java | 8 +- .../data/redis/connection/PoolException.java | 11 +- .../redis/connection/ReactiveGeoCommands.java | 135 ++++++----- .../connection/ReactiveHashCommands.java | 17 +- .../redis/connection/ReactiveKeyCommands.java | 29 ++- .../connection/ReactiveListCommands.java | 73 +++--- .../connection/ReactiveNumberCommands.java | 25 +- .../connection/ReactiveRedisConnection.java | 21 +- .../redis/connection/ReactiveSetCommands.java | 42 ++-- .../connection/ReactiveStringCommands.java | 60 +++-- .../connection/ReactiveZSetCommands.java | 114 +++++---- .../connection/RedisClusterCommands.java | 2 +- .../connection/RedisClusterConfiguration.java | 4 +- .../connection/RedisClusterConnection.java | 13 +- .../redis/connection/RedisClusterNode.java | 48 ++-- .../data/redis/connection/RedisCommands.java | 13 +- .../connection/RedisConnectionCommands.java | 8 +- .../redis/connection/RedisGeoCommands.java | 51 ++-- .../redis/connection/RedisHashCommands.java | 47 ++-- .../connection/RedisHyperLogLogCommands.java | 8 +- .../redis/connection/RedisKeyCommands.java | 60 +++-- .../redis/connection/RedisListCommands.java | 75 +++--- .../data/redis/connection/RedisNode.java | 30 ++- .../connection/RedisPipelineException.java | 3 +- .../redis/connection/RedisPubSubCommands.java | 22 +- .../connection/RedisScriptingCommands.java | 20 +- .../connection/RedisSentinelCommands.java | 2 +- .../RedisSentinelConfiguration.java | 6 +- .../redis/connection/RedisServerCommands.java | 37 +-- .../redis/connection/RedisSetCommands.java | 59 +++-- .../redis/connection/RedisStringCommands.java | 38 +-- .../RedisSubscribedConnectionException.java | 6 +- .../redis/connection/RedisZSetCommands.java | 222 ++++++++++++------ .../data/redis/connection/ReturnType.java | 12 +- .../data/redis/connection/SortParameters.java | 37 +-- .../data/redis/connection/Subscription.java | 27 ++- .../redis/connection/convert/Converters.java | 35 ++- .../connection/convert/ListConverter.java | 12 +- .../convert/LongToBooleanConverter.java | 10 +- .../connection/convert/MapConverter.java | 31 +-- .../convert/MapToPropertiesConverter.java | 15 +- .../connection/convert/SetConverter.java | 31 +-- .../convert/StringToDataTypeConverter.java | 13 +- .../convert/StringToPropertiesConverter.java | 19 +- .../StringToRedisClientInfoConverter.java | 15 +- .../convert/TransactionResultConverter.java | 23 +- .../connection/convert/package-info.java | 5 + .../DefaultJedisClientConfiguration.java | 36 ++- .../jedis/JedisClientConfiguration.java | 9 +- .../jedis/JedisClusterConnection.java | 8 +- .../jedis/JedisClusterServerCommands.java | 5 +- .../jedis/JedisClusterZSetCommands.java | 35 +-- .../connection/jedis/JedisConnection.java | 18 +- .../jedis/JedisConnectionFactory.java | 22 +- .../connection/jedis/JedisServerCommands.java | 5 +- .../connection/jedis/JedisStringCommands.java | 10 +- .../redis/connection/jedis/package-info.java | 2 +- .../DefaultLettuceClientConfiguration.java | 5 +- .../lettuce/DefaultLettucePool.java | 18 +- .../lettuce/LettuceClientConfiguration.java | 5 +- .../lettuce/LettuceClusterConnection.java | 11 +- .../connection/lettuce/LettuceConnection.java | 7 +- .../lettuce/LettuceConnectionFactory.java | 21 +- .../connection/lettuce/LettuceConverters.java | 3 +- .../redis/connection/lettuce/LettucePool.java | 2 + .../LettuceReactiveStringCommands.java | 3 +- .../lettuce/LettuceReactiveZSetCommands.java | 4 +- .../lettuce/LettuceSentinelConnection.java | 2 +- .../lettuce/LettuceServerCommands.java | 5 +- .../lettuce/LettuceStringCommands.java | 4 + .../lettuce/LettuceZSetCommands.java | 145 ++++++------ .../connection/lettuce/package-info.java | 4 +- .../data/redis/connection/package-info.java | 1 + .../connection/util/AbstractSubscription.java | 20 +- .../data/redis/connection/util/Base64.java | 16 +- .../redis/connection/util/DecodeUtils.java | 6 +- .../redis/connection/util/package-info.java | 1 + .../data/redis/core/AbstractOperations.java | 5 +- .../data/redis/core/BoundGeoOperations.java | 77 ++++-- .../data/redis/core/BoundHashOperations.java | 41 ++-- .../data/redis/core/BoundKeyOperations.java | 32 ++- .../data/redis/core/BoundListOperations.java | 50 ++-- .../data/redis/core/BoundSetOperations.java | 66 ++++-- .../data/redis/core/BoundValueOperations.java | 30 ++- .../data/redis/core/BoundZSetOperations.java | 69 ++++-- .../CloseSuppressingInvocationHandler.java | 6 +- .../data/redis/core/ConvertingCursor.java | 2 + .../redis/core/DefaultBoundKeyOperations.java | 7 +- .../core/DefaultBoundZSetOperations.java | 2 +- .../redis/core/DefaultClusterOperations.java | 6 +- .../redis/core/DefaultHashOperations.java | 8 +- .../data/redis/core/DefaultTypedTuple.java | 13 +- .../data/redis/core/GeoOperations.java | 77 ++++-- .../data/redis/core/HashOperations.java | 29 ++- .../data/redis/core/RedisAccessor.java | 8 +- .../data/redis/core/RedisKeyValueAdapter.java | 15 +- .../data/redis/core/RedisOperations.java | 63 +++-- .../data/redis/core/RedisTemplate.java | 27 ++- .../data/redis/core/ScanOptions.java | 7 +- .../data/redis/core/ZSetOperations.java | 98 +++++--- .../redis/core/convert/BinaryConverters.java | 39 +-- .../data/redis/core/convert/Bucket.java | 12 +- .../redis/core/convert/IndexResolver.java | 6 +- .../core/convert/KeyspaceConfiguration.java | 7 +- .../data/redis/core/convert/RedisData.java | 10 +- .../redis/core/convert/SpelIndexResolver.java | 5 +- .../data/redis/core/convert/package-info.java | 5 + .../core/index/RedisIndexDefinition.java | 3 +- .../data/redis/core/index/package-info.java | 5 + .../mapping/BasicRedisPersistentEntity.java | 3 + .../core/mapping/RedisMappingContext.java | 5 +- .../core/mapping/RedisPersistentEntity.java | 2 + .../data/redis/core/mapping/package-info.java | 5 + .../data/redis/core/package-info.java | 8 +- .../core/query/DefaultSortCriterion.java | 12 +- .../data/redis/core/query/package-info.java | 1 + .../redis/core/script/DefaultRedisScript.java | 8 +- .../data/redis/core/script/RedisScript.java | 2 + .../data/redis/core/script/package-info.java | 5 + .../data/redis/core/types/package-info.java | 5 + .../data/redis/hash/package-info.java | 6 +- .../KeyExpirationEventMessageListener.java | 3 +- .../KeyspaceEventMessageListener.java | 6 +- .../RedisMessageListenerContainer.java | 19 +- .../adapter/MessageListenerAdapter.java | 22 +- .../redis/listener/adapter/package-info.java | 7 +- .../data/redis/listener/package-info.java | 4 +- .../data/redis/package-info.java | 7 +- .../redis/repository/cdi/package-info.java | 17 +- .../configuration/package-info.java | 5 + .../redis/repository/core/package-info.java | 5 + .../data/redis/repository/package-info.java | 5 + .../repository/query/RedisOperationChain.java | 11 +- .../redis/repository/query/package-info.java | 5 + .../repository/support/package-info.java | 5 + .../serializer/DefaultRedisElementReader.java | 4 +- .../serializer/DefaultRedisElementWriter.java | 29 ++- .../DefaultRedisSerializationContext.java | 9 +- .../GenericJackson2JsonRedisSerializer.java | 7 +- .../serializer/GenericToStringSerializer.java | 11 +- .../Jackson2JsonRedisSerializer.java | 6 +- .../JdkSerializationRedisSerializer.java | 7 +- .../data/redis/serializer/OxmSerializer.java | 15 +- .../redis/serializer/RedisElementReader.java | 4 +- .../redis/serializer/RedisSerializer.java | 17 +- .../redis/serializer/SerializationUtils.java | 33 ++- .../serializer/StringRedisSerializer.java | 5 +- .../data/redis/serializer/package-info.java | 4 +- .../redis/support/atomic/package-info.java | 4 +- .../collections/AbstractRedisCollection.java | 3 +- .../support/collections/DefaultRedisList.java | 26 +- .../support/collections/DefaultRedisMap.java | 18 +- .../support/collections/DefaultRedisZSet.java | 6 +- .../RedisCollectionFactoryBean.java | 11 +- .../support/collections/RedisIterator.java | 4 +- .../redis/support/collections/RedisStore.java | 2 +- .../support/collections/package-info.java | 17 +- .../data/redis/support/package-info.java | 2 +- .../data/redis/util/ByteUtils.java | 3 +- .../data/redis/util/package-info.java | 5 + .../AbstractConnectionIntegrationTests.java | 39 +-- .../ClusterCommandExecutorUnitTests.java | 2 +- .../jedis/JedisClusterConnectionTests.java | 13 +- .../JedisClusterConnectionUnitTests.java | 27 +-- .../LettuceClusterConnectionTests.java | 18 +- ...pirationEventMessageListenerUnitTests.java | 4 +- 189 files changed, 2285 insertions(+), 1396 deletions(-) create mode 100644 src/main/java/org/springframework/data/redis/config/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/connection/convert/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/core/convert/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/core/index/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/core/mapping/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/core/script/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/core/types/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/repository/configuration/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/repository/core/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/repository/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/repository/query/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/repository/support/package-info.java create mode 100644 src/main/java/org/springframework/data/redis/util/package-info.java diff --git a/src/main/java/org/springframework/data/redis/ExceptionTranslationStrategy.java b/src/main/java/org/springframework/data/redis/ExceptionTranslationStrategy.java index 807829fb5..7ccbf02a3 100644 --- a/src/main/java/org/springframework/data/redis/ExceptionTranslationStrategy.java +++ b/src/main/java/org/springframework/data/redis/ExceptionTranslationStrategy.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. @@ -16,6 +16,7 @@ package org.springframework.data.redis; import org.springframework.dao.DataAccessException; +import org.springframework.lang.Nullable; /** * Potentially translates an {@link Exception} into appropriate {@link DataAccessException}. @@ -28,10 +29,11 @@ public interface ExceptionTranslationStrategy { /** * Potentially translate the given {@link Exception} into {@link DataAccessException}. - * - * @param e - * @return + * + * @param e must not be {@literal null}. + * @return can be {@literal null} if given {@link Exception} cannot be translated. */ + @Nullable DataAccessException translate(Exception e); } diff --git a/src/main/java/org/springframework/data/redis/VersionParser.java b/src/main/java/org/springframework/data/redis/VersionParser.java index f06c02683..ae0663555 100644 --- a/src/main/java/org/springframework/data/redis/VersionParser.java +++ b/src/main/java/org/springframework/data/redis/VersionParser.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. @@ -18,6 +18,8 @@ package org.springframework.data.redis; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.springframework.lang.Nullable; + /** * Central class for reading version string (eg. {@literal 1.3.1}) into {@link Version}. * @@ -31,10 +33,11 @@ public class VersionParser { /** * Parse version string {@literal eg. 1.1.1} to {@link Version}. * - * @param version - * @return + * @param version can be {@literal null}. + * @return never {@literal null}. */ - public static Version parseVersion(String version) { + public static Version parseVersion(@Nullable String version) { + if (version == null) { return Version.UNKNOWN; } @@ -47,6 +50,7 @@ public class VersionParser { return new Version(Integer.parseInt(major), minor != null ? Integer.parseInt(minor) : 0, patch != null ? Integer.parseInt(patch) : 0); } + return Version.UNKNOWN; } diff --git a/src/main/java/org/springframework/data/redis/cache/DefaultRedisCacheWriter.java b/src/main/java/org/springframework/data/redis/cache/DefaultRedisCacheWriter.java index 13867093b..713a9ef48 100644 --- a/src/main/java/org/springframework/data/redis/cache/DefaultRedisCacheWriter.java +++ b/src/main/java/org/springframework/data/redis/cache/DefaultRedisCacheWriter.java @@ -17,6 +17,8 @@ package org.springframework.data.redis.cache; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.util.Collections; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Function; @@ -26,6 +28,7 @@ import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.core.types.Expiration; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -70,17 +73,16 @@ class DefaultRedisCacheWriter implements RedisCacheWriter { this.sleepTime = sleepTime; } - /* + /* * (non-Javadoc) * @see org.springframework.data.redis.cache.RedisCacheWriter#put(java.lang.String, byte[], byte[], java.time.Duration) */ @Override - public void put(String name, byte[] key, byte[] value, Duration ttl) { + public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) { Assert.notNull(name, "Name must not be null!"); Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - Assert.notNull(ttl, "Ttl must not be null!"); execute(name, connection -> { @@ -94,7 +96,7 @@ class DefaultRedisCacheWriter implements RedisCacheWriter { }); } - /* + /* * (non-Javadoc) * @see org.springframework.data.redis.cache.RedisCacheWriter#get(java.lang.String, byte[]) */ @@ -107,17 +109,16 @@ class DefaultRedisCacheWriter implements RedisCacheWriter { return execute(name, connection -> connection.get(key)); } - /* + /* * (non-Javadoc) * @see org.springframework.data.redis.cache.RedisCacheWriter#putIfAbsent(java.lang.String, byte[], byte[], java.time.Duration) */ @Override - public byte[] putIfAbsent(String name, byte[] key, byte[] value, Duration ttl) { + public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) { Assert.notNull(name, "Name must not be null!"); Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); - Assert.notNull(ttl, "Ttl must not be null!"); return execute(name, connection -> { @@ -178,7 +179,8 @@ class DefaultRedisCacheWriter implements RedisCacheWriter { wasLocked = true; } - byte[][] keys = connection.keys(pattern).toArray(new byte[0][]); + byte[][] keys = Optional.ofNullable(connection.keys(pattern)).orElse(Collections.emptySet()) + .toArray(new byte[0][]); if (keys.length > 0) { connection.del(keys); @@ -275,7 +277,7 @@ class DefaultRedisCacheWriter implements RedisCacheWriter { } } - private static boolean shouldExpireWithin(Duration ttl) { + private static boolean shouldExpireWithin(@Nullable Duration ttl) { return ttl != null && !ttl.isZero() && !ttl.isNegative(); } 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 ba3183175..c0fc359eb 100644 --- a/src/main/java/org/springframework/data/redis/cache/RedisCache.java +++ b/src/main/java/org/springframework/data/redis/cache/RedisCache.java @@ -26,6 +26,7 @@ import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.util.ByteUtils; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; @@ -129,7 +130,7 @@ public class RedisCache extends AbstractValueAdaptingCache { * @see org.springframework.cache.Cache#put(java.lang.Object, java.lang.Object) */ @Override - public void put(Object key, Object value) { + public void put(Object key, @Nullable Object value) { Object cacheValue = preProcessCacheValue(value); @@ -148,7 +149,7 @@ public class RedisCache extends AbstractValueAdaptingCache { * @see org.springframework.cache.Cache#putIfAbsent(java.lang.Object, java.lang.Object) */ @Override - public ValueWrapper putIfAbsent(Object key, Object value) { + public ValueWrapper putIfAbsent(Object key, @Nullable Object value) { Object cacheValue = preProcessCacheValue(value); @@ -202,7 +203,8 @@ public class RedisCache extends AbstractValueAdaptingCache { * @param value can be {@literal null}. * @return preprocessed value. Can be {@literal null}. */ - protected Object preProcessCacheValue(Object value) { + @Nullable + protected Object preProcessCacheValue(@Nullable Object value) { if (value != null) { return value; @@ -242,6 +244,7 @@ public class RedisCache extends AbstractValueAdaptingCache { * @param value must not be {@literal null}. * @return can be {@literal null}. */ + @Nullable protected Object deserializeCacheValue(byte[] value) { if (isAllowNullValues() && ObjectUtils.nullSafeEquals(value, BINARY_NULL_VALUE)) { diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCacheConfiguration.java b/src/main/java/org/springframework/data/redis/cache/RedisCacheConfiguration.java index aa347bcee..ff10b5692 100644 --- a/src/main/java/org/springframework/data/redis/cache/RedisCacheConfiguration.java +++ b/src/main/java/org/springframework/data/redis/cache/RedisCacheConfiguration.java @@ -27,6 +27,7 @@ import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.format.support.DefaultFormattingConversionService; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -43,7 +44,7 @@ public class RedisCacheConfiguration { private final Duration ttl; private final boolean cacheNullValues; - private final String keyPrefix; + private final @Nullable String keyPrefix; private final boolean usePrefix; private final SerializationPair keySerializationPair; @@ -52,7 +53,7 @@ public class RedisCacheConfiguration { private final ConversionService conversionService; @SuppressWarnings("unchecked") - private RedisCacheConfiguration(Duration ttl, Boolean cacheNullValues, Boolean usePrefix, String keyPrefix, + private RedisCacheConfiguration(Duration ttl, Boolean cacheNullValues, Boolean usePrefix, @Nullable String keyPrefix, SerializationPair keySerializationPair, SerializationPair valueSerializationPair, ConversionService conversionService) { diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java b/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java index dc778cc09..d6b10749c 100644 --- a/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java +++ b/src/main/java/org/springframework/data/redis/cache/RedisCacheManager.java @@ -26,6 +26,7 @@ import java.util.Set; import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -205,7 +206,7 @@ public class RedisCacheManager extends AbstractTransactionSupportingCacheManager * @param cacheConfig can be {@literal null}. * @return never {@literal null}. */ - protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) { + protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) { return new RedisCache(name, cacheWriter, cacheConfig != null ? cacheConfig : defaultCacheConfig); } diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCacheWriter.java b/src/main/java/org/springframework/data/redis/cache/RedisCacheWriter.java index 7f1527f0e..5846a9c3a 100644 --- a/src/main/java/org/springframework/data/redis/cache/RedisCacheWriter.java +++ b/src/main/java/org/springframework/data/redis/cache/RedisCacheWriter.java @@ -18,6 +18,7 @@ package org.springframework.data.redis.cache; import java.time.Duration; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -66,7 +67,7 @@ public interface RedisCacheWriter { * @param value The value stored for the key. Must not be {@literal null}. * @param ttl Optional expiration time. Can be {@literal null}. */ - void put(String name, byte[] key, byte[] value, Duration ttl); + void put(String name, byte[] key, byte[] value, @Nullable Duration ttl); /** * Get the binary value representation from Redis stored for the given key. @@ -75,7 +76,7 @@ public interface RedisCacheWriter { * @param key must not be {@literal null}. * @return {@literal null} if key does not exist. */ - + @Nullable byte[] get(String name, byte[] key); /** @@ -87,7 +88,8 @@ public interface RedisCacheWriter { * @param ttl Optional expiration time. Can be {@literal null}. * @return {@literal null} if the value has been written, the value stored for the key if it already exists. */ - byte[] putIfAbsent(String name, byte[] key, byte[] value, Duration ttl); + @Nullable + byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl); /** * Remove the given key from Redis. 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 14230b11d..c79b7ed9e 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,5 +1,6 @@ /** - * Package providing a Redis implementation for Spring cache abstraction. + * Package providing a Redis implementation for Spring + * cache abstraction. */ +@org.springframework.lang.NonNullApi package org.springframework.data.redis.cache; - diff --git a/src/main/java/org/springframework/data/redis/config/RedisCollectionParser.java b/src/main/java/org/springframework/data/redis/config/RedisCollectionParser.java index 083148569..417df2c02 100644 --- a/src/main/java/org/springframework/data/redis/config/RedisCollectionParser.java +++ b/src/main/java/org/springframework/data/redis/config/RedisCollectionParser.java @@ -33,6 +33,7 @@ class RedisCollectionParser extends AbstractSimpleBeanDefinitionParser { } protected void postProcess(BeanDefinitionBuilder beanDefinition, Element element) { + String template = element.getAttribute("template"); if (StringUtils.hasText(template)) { beanDefinition.addPropertyReference("template", template); 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 new file mode 100644 index 000000000..0c0b3156c --- /dev/null +++ b/src/main/java/org/springframework/data/redis/config/package-info.java @@ -0,0 +1,5 @@ +/** + * Namespace and configuration. + */ +@org.springframework.lang.NonNullApi +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 d8ea1ade3..95d5ac492 100644 --- a/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/AbstractRedisConnection.java @@ -22,6 +22,8 @@ import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.InvalidDataAccessResourceUsageException; import org.springframework.data.redis.RedisSystemException; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * @author Christoph Strobl @@ -30,7 +32,7 @@ import org.springframework.data.redis.RedisSystemException; */ public abstract class AbstractRedisConnection implements DefaultedRedisConnection { - private RedisSentinelConfiguration sentinelConfiguration; + private @Nullable RedisSentinelConfiguration sentinelConfiguration; private ConcurrentHashMap connectionCache = new ConcurrentHashMap<>(); /* @@ -63,6 +65,8 @@ public abstract class AbstractRedisConnection implements DefaultedRedisConnectio private RedisNode selectActiveSentinel() { + Assert.state(hasRedisSentinelConfigured(), "Sentinel configuration missing!"); + for (RedisNode node : this.sentinelConfiguration.getSentinels()) { if (isActive(node)) { return node; diff --git a/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutor.java b/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutor.java index 194c831ef..a53ba715c 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutor.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterCommandExecutor.java @@ -29,6 +29,7 @@ import org.springframework.data.redis.ExceptionTranslationStrategy; import org.springframework.data.redis.TooManyClusterRedirectionsException; import org.springframework.data.redis.connection.util.ByteArraySet; import org.springframework.data.redis.connection.util.ByteArrayWrapper; +import org.springframework.lang.Nullable; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -73,10 +74,10 @@ public class ClusterCommandExecutor implements DisposableBean { * @param topologyProvider must not be {@literal null}. * @param resourceProvider must not be {@literal null}. * @param exceptionTranslation must not be {@literal null}. - * @param executor can be {@literal null}. + * @param executor can be {@literal null}. Defaulted to {@link ThreadPoolTaskExecutor}. */ public ClusterCommandExecutor(ClusterTopologyProvider topologyProvider, ClusterNodeResourceProvider resourceProvider, - ExceptionTranslationStrategy exceptionTranslation, AsyncTaskExecutor executor) { + ExceptionTranslationStrategy exceptionTranslation, @Nullable AsyncTaskExecutor executor) { this(topologyProvider, resourceProvider, exceptionTranslation); this.executor = executor; @@ -94,7 +95,7 @@ public class ClusterCommandExecutor implements DisposableBean { * Run {@link ClusterCommandCallback} on a random node. * * @param cmd must not be {@literal null}. - * @return + * @return never {@literal null}. */ public NodeResult executeCommandOnArbitraryNode(ClusterCommandCallback cmd) { @@ -325,6 +326,7 @@ public class ClusterCommandExecutor implements DisposableBean { return this.topologyProvider.getTopology(); } + @Nullable private DataAccessException convertToDataAccessExeption(Exception e) { return exceptionTranslationStrategy.translate(e); } @@ -455,27 +457,27 @@ public class ClusterCommandExecutor implements DisposableBean { public static class NodeResult { private RedisClusterNode node; - private T value; + private @Nullable T value; private ByteArrayWrapper key; /** * Create new {@link NodeResult}. * - * @param node - * @param value + * @param node must not be {@literal null}. + * @param value can be {@literal null}. */ - public NodeResult(RedisClusterNode node, T value) { + public NodeResult(RedisClusterNode node, @Nullable T value) { this(node, value, new byte[] {}); } /** * Create new {@link NodeResult}. * - * @param node - * @param value - * @parm key + * @param node must not be {@literal null}. + * @param value can be {@literal null}. + * @param key must not be {@literal null}. */ - public NodeResult(RedisClusterNode node, T value, byte[] key) { + public NodeResult(RedisClusterNode node, @Nullable T value, byte[] key) { this.node = node; this.value = value; @@ -488,6 +490,7 @@ public class ClusterCommandExecutor implements DisposableBean { * * @return can be {@literal null}. */ + @Nullable public T getValue() { return value; } @@ -557,9 +560,10 @@ public class ClusterCommandExecutor implements DisposableBean { /** * @param returnValue can be {@literal null}. - * @return + * @return can be {@litearl null}. */ - public T getFirstNonNullNotEmptyOrDefault(T returnValue) { + @Nullable + public T getFirstNonNullNotEmptyOrDefault(@Nullable T returnValue) { for (NodeResult nodeResult : nodeResults) { if (nodeResult.getValue() != null) { diff --git a/src/main/java/org/springframework/data/redis/connection/ClusterInfo.java b/src/main/java/org/springframework/data/redis/connection/ClusterInfo.java index 354719b52..7dbff90e8 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterInfo.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterInfo.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. @@ -18,6 +18,7 @@ package org.springframework.data.redis.connection; import java.util.Properties; import org.springframework.data.redis.core.types.RedisClientInfo.INFO; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -32,8 +33,8 @@ public class ClusterInfo { public static enum Info { STATE("cluster_state"), SLOTS_ASSIGNED("cluster_slots_assigned"), SLOTS_OK("cluster_slots_ok"), SLOTS_PFAIL( "cluster_slots_pfail"), SLOTS_FAIL("cluster_slots_fail"), KNOWN_NODES("cluster_known_nodes"), SIZE( - "cluster_size"), CURRENT_EPOCH("cluster_current_epoch"), MY_EPOCH("cluster_my_epoch"), MESSAGES_SENT( - "cluster_stats_messages_sent"), MESSAGES_RECEIVED("cluster_stats_messages_received"); + "cluster_size"), CURRENT_EPOCH("cluster_current_epoch"), MY_EPOCH("cluster_my_epoch"), MESSAGES_SENT( + "cluster_stats_messages_sent"), MESSAGES_RECEIVED("cluster_stats_messages_received"); String key; @@ -57,80 +58,90 @@ public class ClusterInfo { /** * @see Info#STATE - * @return + * @return {@literal null} if no entry found for requested {@link Info#STATE}. */ + @Nullable public String getState() { return get(Info.STATE); } /** * @see Info#SLOTS_ASSIGNED - * @return + * @return {@literal null} if no entry found for requested {@link Info#SLOTS_ASSIGNED}. */ + @Nullable public Long getSlotsAssigned() { return getLongValueOf(Info.SLOTS_ASSIGNED); } /** * @see Info#SLOTS_OK - * @return + * @return {@literal null} if no entry found for requested {@link Info#SLOTS_OK}. */ + @Nullable public Long getSlotsOk() { return getLongValueOf(Info.SLOTS_OK); } /** * @see Info#SLOTS_PFAIL - * @return + * @return {@literal null} if no entry found for requested {@link Info#SLOTS_PFAIL}. */ + @Nullable public Long getSlotsPfail() { return getLongValueOf(Info.SLOTS_PFAIL); } /** * @see Info#SLOTS_FAIL - * @return + * @return {@literal null} if no entry found for requested {@link Info#SLOTS_FAIL}. */ + @Nullable public Long getSlotsFail() { return getLongValueOf(Info.SLOTS_FAIL); } /** * @see Info#KNOWN_NODES - * @return + * @return {@literal null} if no entry found for requested {@link Info#KNOWN_NODES}. */ + @Nullable public Long getKnownNodes() { return getLongValueOf(Info.KNOWN_NODES); } /** * @see Info#SIZE - * @return + * @return {@literal null} if no entry found for requested {@link Info#SIZE}. */ + @Nullable public Long getClusterSize() { return getLongValueOf(Info.SIZE); } /** * @see Info#CURRENT_EPOCH - * @return + * @return {@literal null} if no entry found for requested {@link Info#CURRENT_EPOCH}. */ + @Nullable public Long getCurrentEpoch() { return getLongValueOf(Info.CURRENT_EPOCH); } /** * @see Info#MESSAGES_SENT - * @return + * @return {@literal null} if no entry found for requested {@link Info#MESSAGES_SENT}. */ + @Nullable public Long getMessagesSent() { return getLongValueOf(Info.MESSAGES_SENT); } /** * @see Info#MESSAGES_RECEIVED - * @return + * @return {@literal null} if no entry found for requested {@link Info#MESSAGES_RECEIVED}. */ + @Nullable public Long getMessagesReceived() { return getLongValueOf(Info.MESSAGES_RECEIVED); } @@ -139,6 +150,7 @@ public class ClusterInfo { * @param info must not be null * @return {@literal null} if no entry found for requested {@link INFO}. */ + @Nullable public String get(Info info) { Assert.notNull(info, "Cannot retrieve cluster information for 'null'."); @@ -149,12 +161,14 @@ public class ClusterInfo { * @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 cluster information for 'empty' / 'null' key."); return this.clusterProperties.getProperty(key); } + @Nullable private Long getLongValueOf(Info info) { String value = get(info); diff --git a/src/main/java/org/springframework/data/redis/connection/ClusterNodeResourceProvider.java b/src/main/java/org/springframework/data/redis/connection/ClusterNodeResourceProvider.java index 379b74b9d..ce5e9a796 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterNodeResourceProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterNodeResourceProvider.java @@ -28,7 +28,8 @@ public interface ClusterNodeResourceProvider { * Get the client resource for the given node. * * @param node must not be {@literal null}. - * @return + * @return never {@literal null}. + * @throws org.springframework.dao.DataAccessResourceFailureException if node is not known to the cluster. */ S getResourceForSpecificNode(RedisClusterNode node); 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 be689a997..7366138c7 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterTopology.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterTopology.java @@ -20,6 +20,7 @@ import java.util.LinkedHashSet; import java.util.Set; import org.springframework.data.redis.ClusterStateFailureException; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -39,7 +40,7 @@ public class ClusterTopology { * * @param nodes can be {@literal null}. */ - public ClusterTopology(Set nodes) { + public ClusterTopology(@Nullable Set nodes) { this.nodes = nodes != null ? nodes : Collections.emptySet(); } @@ -153,7 +154,7 @@ public class ClusterTopology { public RedisClusterNode lookup(String host, int port) { for (RedisClusterNode node : nodes) { - if (host.equals(node.getHost()) && port == node.getPort()) { + if (host.equals(node.getHost()) && (node.getPort() != null && port == node.getPort())) { return node; } } @@ -199,7 +200,7 @@ public class ClusterTopology { return node; } - if (StringUtils.hasText(node.getHost())) { + if (StringUtils.hasText(node.getHost()) && node.getPort() != null) { return lookup(node.getHost(), node.getPort()); } 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 b3fb569d4..74279ed45 100644 --- a/src/main/java/org/springframework/data/redis/connection/ClusterTopologyProvider.java +++ b/src/main/java/org/springframework/data/redis/connection/ClusterTopologyProvider.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,7 +17,7 @@ package org.springframework.data.redis.connection; /** * {@link ClusterTopologyProvider} manages the current cluster topology and makes sure to refresh cluster information. - * + * * @author Christoph Strobl * @since 1.7 */ @@ -25,7 +25,7 @@ public interface ClusterTopologyProvider { /** * Get the current known {@link ClusterTopology}. - * + * * @return never {@null}. */ ClusterTopology getTopology(); diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultMessage.java b/src/main/java/org/springframework/data/redis/connection/DefaultMessage.java index 946728c5f..1e3d731db 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultMessage.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultMessage.java @@ -1,5 +1,5 @@ /* - * 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. @@ -15,31 +15,44 @@ */ package org.springframework.data.redis.connection; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + /** * Default message implementation. * * @author Costin Leau + * @author Christoph Strobl */ public class DefaultMessage implements Message { private final byte[] channel; private final byte[] body; - private String toString; + private @Nullable String toString; public DefaultMessage(byte[] channel, byte[] body) { + + Assert.notNull(channel, "Channel must not be null!"); + Assert.notNull(body, "Body must not be null!"); + this.body = body; this.channel = channel; } + /** + * @return + */ public byte[] getChannel() { - return (channel != null ? channel.clone() : null); + return channel.clone(); } public byte[] getBody() { - return (body != null ? body.clone() : null); + return body.clone(); } + @Override public String toString() { + if (toString == null) { toString = new String(body); } 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 93abfec78..6cefa04d0 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -48,6 +48,7 @@ import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -3242,8 +3243,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco @Override public Cursor> hScan(String key, ScanOptions options) { - return new ConvertingCursor<>( - this.delegate.hScan(this.serialize(key), options), + return new ConvertingCursor<>(this.delegate.hScan(this.serialize(key), options), source -> new Entry() { @Override @@ -3278,8 +3278,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco */ @Override public Cursor zScan(String key, ScanOptions options) { - return new ConvertingCursor<>(delegate.zScan(this.serialize(key), options), - new TupleConverter()); + return new ConvertingCursor<>(delegate.zScan(this.serialize(key), options), new TupleConverter()); } /* @@ -3440,7 +3439,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption) */ @Override - public void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option) { + public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option) { delegate.migrate(key, target, dbIndex, option); } @@ -3449,7 +3448,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption, long) */ @Override - public void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option, long timeout) { + public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, long timeout) { delegate.migrate(key, target, dbIndex, option, timeout); } @@ -3467,10 +3466,13 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco private T convertAndReturn(Object value, Converter converter) { if (isFutureConversion()) { + addResultConverter(converter); + return null; } - return ObjectUtils.nullSafeEquals(converter, identityConverter) ? (T) value : (T) converter.convert(value); + + return value == null ? null : ObjectUtils.nullSafeEquals(converter, identityConverter) ? (T) value : (T) converter.convert(value); } private void addResultConverter(Converter converter) { @@ -3497,7 +3499,9 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco } List convertedResults = new ArrayList<>(results.size()); for (Object result : results) { - convertedResults.add(converters.remove().convert(result)); + + Converter converter = converters.remove(); + convertedResults.add(result == null ? null : converter.convert(result)); } return convertedResults; } diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultTuple.java b/src/main/java/org/springframework/data/redis/connection/DefaultTuple.java index de2fd984f..bf52849f2 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultTuple.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultTuple.java @@ -1,5 +1,5 @@ /* - * 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. @@ -21,8 +21,9 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; /** * Default implementation for {@link Tuple} interface. - * + * * @author Costin Leau + * @author Christoph Strobl */ public class DefaultTuple implements Tuple { @@ -36,14 +37,23 @@ public class DefaultTuple implements Tuple { * @param score */ public DefaultTuple(byte[] value, Double score) { + this.score = score; this.value = value; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands.Tuple#getScore() + */ public Double getScore() { return score; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.connection.RedisZSetCommands.Tuple#getValue() + */ public byte[] getValue() { return value; } 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 60b89aa8f..8de0c63d3 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultedRedisConnection.java @@ -31,6 +31,7 @@ import org.springframework.data.redis.core.Cursor; 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; /** * {@link DefaultedRedisConnection} provides method delegates to {@code Redis*Command} interfaces accessible via @@ -1184,14 +1185,14 @@ public interface DefaultedRedisConnection extends RedisConnection { /** @deprecated in favor of {@link RedisConnection#serverCommands()}. */ @Override @Deprecated - default void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option) { + default void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option) { serverCommands().migrate(key, target, dbIndex, option); } /** @deprecated in favor of {@link RedisConnection#serverCommands()}. */ @Override @Deprecated - default void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option, long timeout) { + default void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, long timeout) { serverCommands().migrate(key, target, dbIndex, option, timeout); } 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 431ae5b28..704b5fa52 100644 --- a/src/main/java/org/springframework/data/redis/connection/FutureResult.java +++ b/src/main/java/org/springframework/data/redis/connection/FutureResult.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. @@ -16,11 +16,13 @@ package org.springframework.data.redis.connection; import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; /** * The result of an asynchronous operation * * @author Jennifer Hickey + * @author Christoph Strobl * @param The data type of the object that holds the future result (usually of type Future) */ abstract public class FutureResult { @@ -29,7 +31,8 @@ abstract public class FutureResult { protected boolean status = false; - @SuppressWarnings("rawtypes") protected Converter converter; + @SuppressWarnings("rawtypes") // + protected @Nullable Converter converter; public FutureResult(T resultHolder) { this.resultHolder = resultHolder; @@ -48,18 +51,22 @@ abstract public class FutureResult { /** * Converts the given result if a converter is specified, else returns the result * - * @param result The result to convert - * @return The converted result + * @param result The result to convert. Can be {@literal null}. + * @return The converted result or {@literal null}. */ @SuppressWarnings("unchecked") - public Object convert(Object result) { - if (converter != null) { - return converter.convert(result); + @Nullable + public Object convert(@Nullable Object result) { + + if (result == null) { + return null; } - return result; + + return (converter != null) ? converter.convert(result) : result; } @SuppressWarnings("rawtypes") + @Nullable public Converter getConverter() { return converter; } @@ -81,7 +88,8 @@ abstract public class FutureResult { } /** - * @return The result of the operation + * @return The result of the operation. Can be {@literal null}. */ + @Nullable abstract public Object get(); } diff --git a/src/main/java/org/springframework/data/redis/connection/Message.java b/src/main/java/org/springframework/data/redis/connection/Message.java index 1547fb1f6..bfea26a58 100644 --- a/src/main/java/org/springframework/data/redis/connection/Message.java +++ b/src/main/java/org/springframework/data/redis/connection/Message.java @@ -1,5 +1,5 @@ /* - * 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. @@ -17,24 +17,27 @@ package org.springframework.data.redis.connection; import java.io.Serializable; +import org.springframework.lang.Nullable; + /** * Class encapsulating a Redis message body and its properties. - * + * * @author Costin Leau + * @author Christoph Strobl */ public interface Message extends Serializable { /** * Returns the body (or the payload) of the message. - * - * @return message body + * + * @return message body. Never {@literal null}. */ byte[] getBody(); /** * Returns the channel associated with the message. - * - * @return message channel. + * + * @return message channel. Never {@literal null}. */ byte[] getChannel(); } diff --git a/src/main/java/org/springframework/data/redis/connection/MessageListener.java b/src/main/java/org/springframework/data/redis/connection/MessageListener.java index b51729340..41811f850 100644 --- a/src/main/java/org/springframework/data/redis/connection/MessageListener.java +++ b/src/main/java/org/springframework/data/redis/connection/MessageListener.java @@ -1,5 +1,5 @@ /* - * 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. @@ -15,18 +15,21 @@ */ package org.springframework.data.redis.connection; +import org.springframework.lang.Nullable; + /** * Listener of messages published in Redis. - * + * * @author Costin Leau + * @author Christoph Strobl */ public interface MessageListener { /** * Callback for processing received objects through Redis. - * - * @param message message - * @param pattern pattern matching the channel (if specified) - can be null + * + * @param message message must not be {@literal null}. + * @param pattern pattern matching the channel (if specified) - can be {@literal null}. */ - void onMessage(Message message, byte[] pattern); + void onMessage(Message message, @Nullable byte[] pattern); } diff --git a/src/main/java/org/springframework/data/redis/connection/NamedNode.java b/src/main/java/org/springframework/data/redis/connection/NamedNode.java index e5c0be670..c4f069c6b 100644 --- a/src/main/java/org/springframework/data/redis/connection/NamedNode.java +++ b/src/main/java/org/springframework/data/redis/connection/NamedNode.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,11 +15,17 @@ */ package org.springframework.data.redis.connection; +import org.springframework.lang.Nullable; + /** * @author Christoph Strobl * @since 1.4 */ public interface NamedNode { + /** + * @return the node name. Can be {@literal null}. + */ + @Nullable String getName(); } 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 a8abd7168..acc09f724 100644 --- a/src/main/java/org/springframework/data/redis/connection/PoolException.java +++ b/src/main/java/org/springframework/data/redis/connection/PoolException.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. @@ -16,27 +16,30 @@ package org.springframework.data.redis.connection; import org.springframework.core.NestedRuntimeException; +import org.springframework.lang.Nullable; /** * Exception thrown when there are issues with a resource pool * * @author Jennifer Hickey + * @author Christoph Strobl */ @SuppressWarnings("serial") public class PoolException extends NestedRuntimeException { + /** * Constructs a new PoolException instance. - * + * * @param msg * @param cause */ - public PoolException(String msg, Throwable cause) { + public PoolException(@Nullable String msg, @Nullable Throwable cause) { super(msg, cause); } /** * Constructs a new PoolException instance. - * + * * @param msg */ public PoolException(String msg) { diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveGeoCommands.java index ce897c46b..4aafb1fb3 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveGeoCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveGeoCommands.java @@ -41,6 +41,7 @@ import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.Flag; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -62,7 +63,7 @@ public interface ReactiveGeoCommands { private final List> geoLocations; - private GeoAddCommand(ByteBuffer key, List> geoLocations) { + private GeoAddCommand(@Nullable ByteBuffer key, List> geoLocations) { super(key); @@ -184,7 +185,8 @@ public interface ReactiveGeoCommands { private final ByteBuffer to; private final Metric metric; - private GeoDistCommand(ByteBuffer key, ByteBuffer from, ByteBuffer to, Metric metric) { + private GeoDistCommand(@Nullable ByteBuffer key, @Nullable ByteBuffer from, @Nullable ByteBuffer to, + Metric metric) { super(key); @@ -274,21 +276,23 @@ public interface ReactiveGeoCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getFrom() { return from; } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getTo() { return to; } /** - * @return + * @return never {@literal null}. */ public Optional getMetric() { return Optional.ofNullable(metric); @@ -305,7 +309,7 @@ public interface ReactiveGeoCommands { * @see Redis Documentation: GEODIST */ default Mono geoDist(ByteBuffer key, ByteBuffer from, ByteBuffer to) { - return geoDist(key, from, to, null); + return geoDist(key, from, to, DistanceUnit.METERS); } /** @@ -314,7 +318,7 @@ public interface ReactiveGeoCommands { * @param key must not be {@literal null}. * @param from must not be {@literal null}. * @param to must not be {@literal null}. - * @param metric can be {@literal null} and defaults to {@link DistanceUnit#METERS}. + * @param metric must not be {@literal null}. * @return * @see Redis Documentation: GEODIST */ @@ -323,6 +327,7 @@ public interface ReactiveGeoCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(from, "From must not be null!"); Assert.notNull(to, "To must not be null!"); + Assert.notNull(metric, "Metric must not be null!"); return geoDist(Mono.just(GeoDistCommand.units(metric).between(from).and(to).forKey(key))) // .next() // @@ -348,7 +353,7 @@ public interface ReactiveGeoCommands { private final List members; - private GeoHashCommand(ByteBuffer key, List members) { + private GeoHashCommand(@Nullable ByteBuffer key, List members) { super(key); @@ -395,7 +400,7 @@ public interface ReactiveGeoCommands { } /** - * @return + * @return never {@literal null}. */ public List getMembers() { return members; @@ -455,7 +460,7 @@ public interface ReactiveGeoCommands { private final List members; - private GeoPosCommand(ByteBuffer key, List members) { + private GeoPosCommand(@Nullable ByteBuffer key, List members) { super(key); @@ -502,7 +507,7 @@ public interface ReactiveGeoCommands { } /** - * @return + * @return never {@literal null}. */ public List getMembers() { return members; @@ -559,19 +564,19 @@ public interface ReactiveGeoCommands { class GeoRadiusCommand extends KeyCommand { private final Distance distance; - private final Point point; + private final @Nullable Point point; private final GeoRadiusCommandArgs args; - private final ByteBuffer store; - private final ByteBuffer storeDist; + private final @Nullable ByteBuffer store; + private final @Nullable ByteBuffer storeDist; - private GeoRadiusCommand(ByteBuffer key, Point point, Distance distance, GeoRadiusCommandArgs args, - ByteBuffer store, ByteBuffer storeDist) { + private GeoRadiusCommand(@Nullable ByteBuffer key, @Nullable Point point, Distance distance, + GeoRadiusCommandArgs args, @Nullable ByteBuffer store, @Nullable ByteBuffer storeDist) { super(key); this.distance = distance; this.point = point; - this.args = args == null ? GeoRadiusCommandArgs.newGeoRadiusArgs() : args; + this.args = args; this.store = store; this.storeDist = storeDist; } @@ -586,7 +591,7 @@ public interface ReactiveGeoCommands { Assert.notNull(distance, "Distance must not be null!"); - return new GeoRadiusCommand(null, null, distance, null, null, null); + return new GeoRadiusCommand(null, null, distance, GeoRadiusCommandArgs.newGeoRadiusArgs(), null, null); } /** @@ -694,11 +699,14 @@ public interface ReactiveGeoCommands { * Applies command {@link GeoRadiusCommandArgs}. Constructs a new command instance with all previously configured * properties. * - * @param args can be {@literal null}. + * @param args must not be {@literal null}. * @return a new {@link GeoRadiusCommand} with {@link GeoRadiusCommandArgs} applied. */ public GeoRadiusCommand withArgs(GeoRadiusCommandArgs args) { - return new GeoRadiusCommand(getKey(), point, distance, args, store, storeDist); + + Assert.notNull(args, "Args must not be null!"); + return new GeoRadiusCommand(getKey(), point, distance, + args == null ? GeoRadiusCommandArgs.newGeoRadiusArgs() : args, store, storeDist); } /** @@ -766,74 +774,79 @@ public interface ReactiveGeoCommands { /** * NOTE: STORE option is not compatible with WITHDIST, WITHHASH and WITHCOORDS options. * - * @param key - * @return + * @param key must not be {@literal null}. + * @return new instance of {@link GeoRadiusCommand}. */ public GeoRadiusCommand storeAt(ByteBuffer key) { + + Assert.notNull(key, "Key must not be null!"); return new GeoRadiusCommand(getKey(), point, distance, args, key, storeDist); } /** * NOTE: STOREDIST option is not compatible with WITHDIST, WITHHASH and WITHCOORDS options. * - * @param key - * @return + * @param key must not be {@literal null}. + * @return new instance of {@link GeoRadiusCommand}. */ - public GeoRadiusCommand storeDistAt(ByteBuffer key) { + public GeoRadiusCommand storeDistAt(@Nullable ByteBuffer key) { + + Assert.notNull(key, "Key must not be null!"); return new GeoRadiusCommand(getKey(), point, distance, args, store, key); } /** - * @return + * @return never {@literal null}. */ public Optional getDirection() { return Optional.ofNullable(args.getSortDirection()); } /** - * @return + * @return never {@literal null}. */ public Distance getDistance() { return distance; } /** - * @return + * @return never {@literal null}. */ public Set getFlags() { return args.getFlags(); } /** - * @return + * @return never {@literal null}. */ public Optional getLimit() { return Optional.ofNullable(args.getLimit()); } /** - * @return + * @return can be {@literal null}. */ + @Nullable public Point getPoint() { return point; } /** - * @return + * @return never {@literal null}. */ public Optional getStore() { return Optional.ofNullable(store); } /** - * @return + * @return never {@literal null}. */ public Optional getStoreDist() { return Optional.ofNullable(storeDist); } /** - * @return + * @return never {@literal null}. */ public Optional getArgs() { return Optional.ofNullable(args); @@ -858,7 +871,7 @@ public interface ReactiveGeoCommands { * @see Redis Documentation: GEORADIUS */ default Flux>> geoRadius(ByteBuffer key, Circle circle) { - return geoRadius(key, circle, null); + return geoRadius(key, circle, GeoRadiusCommandArgs.newGeoRadiusArgs()); } /** @@ -866,7 +879,7 @@ public interface ReactiveGeoCommands { * * @param key must not be {@literal null}. * @param circle must not be {@literal null}. - * @param geoRadiusArgs can be {@literal null}. + * @param geoRadiusArgs must not be {@literal null}. * @return * @see Redis Documentation: GEORADIUS */ @@ -875,6 +888,7 @@ public interface ReactiveGeoCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(circle, "Circle must not be null!"); + Assert.notNull(geoRadiusArgs, "GeoRadiusArgs must not be null!"); return geoRadius(Mono.just(GeoRadiusCommand.within(circle).withArgs(geoRadiusArgs).forKey(key))) .flatMap(CommandResponse::getOutput); @@ -899,19 +913,19 @@ public interface ReactiveGeoCommands { class GeoRadiusByMemberCommand extends KeyCommand { private final Distance distance; - private final ByteBuffer member; + private final @Nullable ByteBuffer member; private final GeoRadiusCommandArgs args; - private final ByteBuffer store; - private final ByteBuffer storeDist; + private final @Nullable ByteBuffer store; + private final @Nullable ByteBuffer storeDist; - private GeoRadiusByMemberCommand(ByteBuffer key, ByteBuffer member, Distance distance, GeoRadiusCommandArgs args, - ByteBuffer store, ByteBuffer storeDist) { + private GeoRadiusByMemberCommand(@Nullable ByteBuffer key, @Nullable ByteBuffer member, Distance distance, + GeoRadiusCommandArgs args, @Nullable ByteBuffer store, @Nullable ByteBuffer storeDist) { super(key); this.distance = distance; this.member = member; - this.args = args == null ? GeoRadiusCommandArgs.newGeoRadiusArgs() : args; + this.args = args; this.store = store; this.storeDist = storeDist; } @@ -1020,11 +1034,12 @@ public interface ReactiveGeoCommands { * Applies command {@link GeoRadiusCommandArgs}. Constructs a new command instance with all previously configured * properties. * - * @param args can be {@literal null}. + * @param args must not be {@literal null}. * @return a new {@link GeoRadiusByMemberCommand} with {@link GeoRadiusCommandArgs} applied. */ public GeoRadiusByMemberCommand withArgs(GeoRadiusCommandArgs args) { + Assert.notNull(args, "Args must not be null!"); return new GeoRadiusByMemberCommand(getKey(), member, distance, args, store, storeDist); } @@ -1084,80 +1099,87 @@ public interface ReactiveGeoCommands { * @return a new {@link GeoRadiusByMemberCommand} with {@literal key} applied. */ public GeoRadiusByMemberCommand forKey(ByteBuffer key) { + + Assert.notNull(key, "Key must not be null!"); return new GeoRadiusByMemberCommand(key, member, distance, args, store, storeDist); } /** * NOTE: STORE option is not compatible with WITHDIST, WITHHASH and WITHCOORDS options. * - * @param key - * @return + * @param key must not be {@literal null}. + * @return new instance of {@link GeoRadiusByMemberCommand}. */ public GeoRadiusByMemberCommand storeAt(ByteBuffer key) { + + Assert.notNull(key, "Key must not be null!"); return new GeoRadiusByMemberCommand(getKey(), member, distance, args, key, storeDist); } /** * NOTE: STOREDIST option is not compatible with WITHDIST, WITHHASH and WITHCOORDS options. * - * @param key - * @return + * @param key must not be {@literal null}. + * @return new instance of {@link GeoRadiusByMemberCommand}. */ public GeoRadiusByMemberCommand storeDistAt(ByteBuffer key) { + + Assert.notNull(key, "Key must not be null!"); return new GeoRadiusByMemberCommand(getKey(), member, distance, args, store, key); } /** - * @return + * @return never {@literal null}. */ public Optional getDirection() { return Optional.ofNullable(args.getSortDirection()); } /** - * @return + * @return never {@literal null}. */ public Distance getDistance() { return distance; } /** - * @return + * @return never {@literal null}. */ public Set getFlags() { return args.getFlags(); } /** - * @return + * @return never {@literal null}. */ public Optional getLimit() { return Optional.ofNullable(args.getLimit()); } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getMember() { return member; } /** - * @return + * @return never {@literal null}. */ public Optional getStore() { return Optional.ofNullable(store); } /** - * @return + * @return never {@literal null}. */ public Optional getStoreDist() { return Optional.ofNullable(storeDist); } /** - * @return + * @return never {@literal null}. */ public Optional getArgs() { return Optional.ofNullable(args); @@ -1183,7 +1205,7 @@ public interface ReactiveGeoCommands { */ default Flux>> geoRadiusByMember(ByteBuffer key, ByteBuffer member, Distance distance) { - return geoRadiusByMember(key, member, distance, null); + return geoRadiusByMember(key, member, distance, GeoRadiusCommandArgs.newGeoRadiusArgs()); } /** @@ -1191,7 +1213,7 @@ public interface ReactiveGeoCommands { * * @param key must not be {@literal null}. * @param member must not be {@literal null}. - * @param geoRadiusArgs can be {@literal null}. + * @param geoRadiusArgs must not be {@literal null}. * @return * @see Redis Documentation: GEORADIUSBYMEMBER */ @@ -1201,6 +1223,7 @@ public interface ReactiveGeoCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(member, "Member must not be null!"); Assert.notNull(distance, "Distance must not be null!"); + Assert.notNull(geoRadiusArgs, "GeoRadiusArgs must not be null!"); return geoRadiusByMember( Mono.just(GeoRadiusByMemberCommand.within(distance).from(member).forKey(key).withArgs(geoRadiusArgs))) diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveHashCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveHashCommands.java index bac54a669..03979020d 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveHashCommands.java @@ -33,6 +33,7 @@ import org.springframework.data.redis.connection.ReactiveRedisConnection.Command import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand; import org.springframework.data.redis.connection.ReactiveRedisConnection.MultiValueResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -56,7 +57,7 @@ public interface ReactiveHashCommands { private final Map fieldValueMap; private final boolean upsert; - private HSetCommand(ByteBuffer key, Map keyValueMap, boolean upsert) { + private HSetCommand(@Nullable ByteBuffer key, Map keyValueMap, boolean upsert) { super(key); @@ -137,7 +138,7 @@ public interface ReactiveHashCommands { } /** - * @return + * @return never {@literal null}. */ public Map getFieldValueMap() { return fieldValueMap; @@ -217,7 +218,7 @@ public interface ReactiveHashCommands { private List fields; - private HGetCommand(ByteBuffer key, List fields) { + private HGetCommand(@Nullable ByteBuffer key, List fields) { super(key); @@ -264,7 +265,7 @@ public interface ReactiveHashCommands { } /** - * @return + * @return never {@literal null}. */ public List getFields() { return fields; @@ -318,7 +319,7 @@ public interface ReactiveHashCommands { private final ByteBuffer field; - private HExistsCommand(ByteBuffer key, ByteBuffer field) { + private HExistsCommand(@Nullable ByteBuffer key, ByteBuffer field) { super(key); @@ -352,7 +353,7 @@ public interface ReactiveHashCommands { } /** - * @return + * @return never {@literal null}. */ public ByteBuffer getField() { return field; @@ -392,7 +393,7 @@ public interface ReactiveHashCommands { private final List fields; - private HDelCommand(ByteBuffer key, List fields) { + private HDelCommand(@Nullable ByteBuffer key, List fields) { super(key); @@ -439,7 +440,7 @@ public interface ReactiveHashCommands { } /** - * @return + * @return never {@literal null}. */ public List getFields() { return fields; diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveKeyCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveKeyCommands.java index ab6bf52c2..306c15de8 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveKeyCommands.java @@ -29,6 +29,7 @@ import org.springframework.data.redis.connection.ReactiveRedisConnection.Command import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand; import org.springframework.data.redis.connection.ReactiveRedisConnection.MultiValueResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -125,9 +126,9 @@ public interface ReactiveKeyCommands { */ class RenameCommand extends KeyCommand { - private ByteBuffer newName; + private @Nullable ByteBuffer newName; - private RenameCommand(ByteBuffer key, ByteBuffer newName) { + private RenameCommand(ByteBuffer key, @Nullable ByteBuffer newName) { super(key); @@ -161,8 +162,9 @@ public interface ReactiveKeyCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getNewName() { return newName; } @@ -271,9 +273,9 @@ public interface ReactiveKeyCommands { */ class ExpireCommand extends KeyCommand { - private Duration timeout; + private @Nullable Duration timeout; - private ExpireCommand(ByteBuffer key, Duration timeout) { + private ExpireCommand(ByteBuffer key, @Nullable Duration timeout) { super(key); @@ -307,8 +309,9 @@ public interface ReactiveKeyCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public Duration getTimeout() { return timeout; } @@ -375,9 +378,9 @@ public interface ReactiveKeyCommands { */ class ExpireAtCommand extends KeyCommand { - private Instant expireAt; + private @Nullable Instant expireAt; - private ExpireAtCommand(ByteBuffer key, Instant expireAt) { + private ExpireAtCommand(ByteBuffer key, @Nullable Instant expireAt) { super(key); @@ -411,8 +414,9 @@ public interface ReactiveKeyCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public Instant getExpireAt() { return expireAt; } @@ -547,9 +551,9 @@ public interface ReactiveKeyCommands { */ class MoveCommand extends KeyCommand { - private Integer database; + private @Nullable Integer database; - private MoveCommand(ByteBuffer key, Integer database) { + private MoveCommand(ByteBuffer key, @Nullable Integer database) { super(key); @@ -581,8 +585,9 @@ public interface ReactiveKeyCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public Integer getDatabase() { return database; } 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 5341969ae..64125b7a4 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveListCommands.java @@ -33,6 +33,7 @@ import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyComm import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.RangeCommand; import org.springframework.data.redis.connection.RedisListCommands.Position; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -65,7 +66,7 @@ public interface ReactiveListCommands { private boolean upsert; private Direction direction; - private PushCommand(ByteBuffer key, List values, Direction direction, boolean upsert) { + private PushCommand(@Nullable ByteBuffer key, List values, Direction direction, boolean upsert) { super(key); @@ -80,7 +81,7 @@ public interface ReactiveListCommands { * @return a new {@link PushCommand} for right push ({@literal RPUSH}). */ public static PushCommand right() { - return new PushCommand(null, null, Direction.RIGHT, true); + return new PushCommand(null, Collections.emptyList(), Direction.RIGHT, true); } /** @@ -89,7 +90,7 @@ public interface ReactiveListCommands { * @return a new {@link PushCommand} for left push ({@literal LPUSH}). */ public static PushCommand left() { - return new PushCommand(null, null, Direction.LEFT, true); + return new PushCommand(null, Collections.emptyList(), Direction.LEFT, true); } /** @@ -141,7 +142,7 @@ public interface ReactiveListCommands { } /** - * @return + * @return never {@literal null}. */ public List getValues() { return values; @@ -155,7 +156,7 @@ public interface ReactiveListCommands { } /** - * @return + * @return never {@literal null}. */ public Direction getDirection() { return direction; @@ -321,7 +322,7 @@ public interface ReactiveListCommands { private final Long index; - private LIndexCommand(ByteBuffer key, Long index) { + private LIndexCommand(@Nullable ByteBuffer key, Long index) { super(key); this.index = index; @@ -390,11 +391,12 @@ public interface ReactiveListCommands { */ class LInsertCommand extends KeyCommand { - private final Position position; - private final ByteBuffer pivot; + private final @Nullable Position position; + private final @Nullable ByteBuffer pivot; private final ByteBuffer value; - private LInsertCommand(ByteBuffer key, Position position, ByteBuffer pivot, ByteBuffer value) { + private LInsertCommand(@Nullable ByteBuffer key, @Nullable Position position, @Nullable ByteBuffer pivot, + ByteBuffer value) { super(key); @@ -456,22 +458,24 @@ public interface ReactiveListCommands { } /** - * @return + * @return never {@literal null}. */ public ByteBuffer getValue() { return value; } /** - * @return + * @return can be {@literal null}. */ + @Nullable public Position getPosition() { return position; } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getPivot() { return pivot; } @@ -520,9 +524,9 @@ public interface ReactiveListCommands { class LSetCommand extends KeyCommand { private final Long index; - private final ByteBuffer value; + private final @Nullable ByteBuffer value; - private LSetCommand(ByteBuffer key, Long index, ByteBuffer value) { + private LSetCommand(@Nullable ByteBuffer key, Long index, @Nullable ByteBuffer value) { super(key); this.index = index; @@ -566,14 +570,15 @@ public interface ReactiveListCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getValue() { return value; } /** - * @return + * @return never {@literal null}. */ public Long getIndex() { return index; @@ -615,9 +620,9 @@ public interface ReactiveListCommands { class LRemCommand extends KeyCommand { private final Long count; - private final ByteBuffer value; + private final @Nullable ByteBuffer value; - private LRemCommand(ByteBuffer key, Long count, ByteBuffer value) { + private LRemCommand(@Nullable ByteBuffer key, Long count, @Nullable ByteBuffer value) { super(key); @@ -681,15 +686,16 @@ public interface ReactiveListCommands { } /** - * @return + * @return never {@literal null}. */ public Long getCount() { return count; } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getValue() { return value; } @@ -751,7 +757,7 @@ public interface ReactiveListCommands { private final Direction direction; - private PopCommand(ByteBuffer key, Direction direction) { + private PopCommand(@Nullable ByteBuffer key, Direction direction) { super(key); @@ -790,7 +796,7 @@ public interface ReactiveListCommands { } /** - * @return + * @return never {@literal null}. */ public Direction getDirection() { return direction; @@ -859,7 +865,7 @@ public interface ReactiveListCommands { * @return a new {@link BPopCommand} for right push ({@literal BRPOP}). */ public static BPopCommand right() { - return new BPopCommand(null, Duration.ZERO, Direction.RIGHT); + return new BPopCommand(Collections.emptyList(), Duration.ZERO, Direction.RIGHT); } /** @@ -868,7 +874,7 @@ public interface ReactiveListCommands { * @return a new {@link BPopCommand} for right push ({@literal BLPOP}). */ public static BPopCommand left() { - return new BPopCommand(null, Duration.ZERO, Direction.LEFT); + return new BPopCommand(Collections.emptyList(), Duration.ZERO, Direction.LEFT); } /** @@ -959,7 +965,6 @@ public interface ReactiveListCommands { * @author Christoph Strobl */ class PopResponse extends CommandResponse { - public PopResponse(BPopCommand input, PopResult output) { super(input, output); } @@ -1019,9 +1024,9 @@ public interface ReactiveListCommands { */ class RPopLPushCommand extends KeyCommand { - private final ByteBuffer destination; + private final @Nullable ByteBuffer destination; - private RPopLPushCommand(ByteBuffer key, ByteBuffer destination) { + private RPopLPushCommand(ByteBuffer key, @Nullable ByteBuffer destination) { super(key); this.destination = destination; @@ -1055,8 +1060,9 @@ public interface ReactiveListCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getDestination() { return destination; } @@ -1098,10 +1104,10 @@ public interface ReactiveListCommands { */ class BRPopLPushCommand extends KeyCommand { - private final ByteBuffer destination; + private final @Nullable ByteBuffer destination; private final Duration timeout; - private BRPopLPushCommand(ByteBuffer key, ByteBuffer destination, Duration timeout) { + private BRPopLPushCommand(ByteBuffer key, @Nullable ByteBuffer destination, Duration timeout) { super(key); @@ -1119,7 +1125,7 @@ public interface ReactiveListCommands { Assert.notNull(sourceKey, "Source key must not be null!"); - return new BRPopLPushCommand(sourceKey, null, null); + return new BRPopLPushCommand(sourceKey, null, Duration.ZERO); } /** @@ -1150,14 +1156,15 @@ public interface ReactiveListCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getDestination() { return destination; } /** - * @return + * @return never {@literal null}. */ public Duration getTimeout() { return timeout; diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveNumberCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveNumberCommands.java index 17f2579f4..cd8cc1dd2 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveNumberCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveNumberCommands.java @@ -23,6 +23,7 @@ import java.nio.ByteBuffer; import org.reactivestreams.Publisher; import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand; import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -65,9 +66,10 @@ public interface ReactiveNumberCommands { */ class IncrByCommand extends KeyCommand { - private T value; + private @Nullable T value; + + private IncrByCommand(ByteBuffer key, @Nullable T value) { - private IncrByCommand(ByteBuffer key, T value) { super(key); this.value = value; } @@ -100,8 +102,9 @@ public interface ReactiveNumberCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public T getValue() { return value; } @@ -141,9 +144,9 @@ public interface ReactiveNumberCommands { */ class DecrByCommand extends KeyCommand { - private T value; + private @Nullable T value; - private DecrByCommand(ByteBuffer key, T value) { + private DecrByCommand(ByteBuffer key, @Nullable T value) { super(key); this.value = value; } @@ -176,8 +179,9 @@ public interface ReactiveNumberCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public T getValue() { return value; } @@ -239,9 +243,9 @@ public interface ReactiveNumberCommands { class HIncrByCommand extends KeyCommand { private final ByteBuffer field; - private final T value; + private final @Nullable T value; - private HIncrByCommand(ByteBuffer key, ByteBuffer field, T value) { + private HIncrByCommand(@Nullable ByteBuffer key, ByteBuffer field, @Nullable T value) { super(key); @@ -290,14 +294,15 @@ public interface ReactiveNumberCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public T getValue() { return value; } /** - * @return + * @return never {@literal null}. */ public ByteBuffer getField() { return field; diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/ReactiveRedisConnection.java index 0bf775474..46de3d6d2 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveRedisConnection.java @@ -24,6 +24,7 @@ import java.util.List; import org.springframework.data.domain.Range; import org.springframework.data.domain.Range.Bound; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -148,6 +149,7 @@ public interface ReactiveRedisConnection extends Closeable { /** * @return the key related to this command. */ + @Nullable ByteBuffer getKey(); /** @@ -165,18 +167,19 @@ public interface ReactiveRedisConnection extends Closeable { */ class KeyCommand implements Command { - private ByteBuffer key; + private @Nullable ByteBuffer key; /** * Creates a new {@link KeyCommand} given a {@code key}. * - * @param key must not be {@literal null}. + * @param key can be {@literal null}. */ - public KeyCommand(ByteBuffer key) { + public KeyCommand(@Nullable ByteBuffer key) { this.key = key; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.ReactiveRedisConnection.Command#getKey() */ @Override @@ -196,12 +199,12 @@ public interface ReactiveRedisConnection extends Closeable { * Creates a new {@link RangeCommand} given a {@code key} and {@link Range}. * * @param key must not be {@literal null}. - * @param range may be {@literal null} if unbounded. + * @param range must not be {@literal null}. */ private RangeCommand(ByteBuffer key, Range range) { super(key); - this.range = range != null ? range : new Range<>(0L, Long.MAX_VALUE); + this.range = range; } /** @@ -211,7 +214,7 @@ public interface ReactiveRedisConnection extends Closeable { * @return a new {@link RangeCommand} for {@code key}. */ public static RangeCommand key(ByteBuffer key) { - return new RangeCommand(key, null); + return new RangeCommand(key, Range.unbounded()); } /** @@ -267,7 +270,7 @@ public interface ReactiveRedisConnection extends Closeable { class CommandResponse { private final I input; - private final O output; + private final @Nullable O output; /** * @return {@literal true} if the response is present. An absent {@link CommandResponse} maps to Redis @@ -293,7 +296,7 @@ public interface ReactiveRedisConnection extends Closeable { */ class ByteBufferResponse extends CommandResponse { - public ByteBufferResponse(I input, ByteBuffer output) { + public ByteBufferResponse(I input, @Nullable ByteBuffer output) { super(input, output); } } diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveSetCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveSetCommands.java index 2b83fd3c3..f949889c3 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveSetCommands.java @@ -32,6 +32,7 @@ import org.springframework.data.redis.connection.ReactiveRedisConnection.Command import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand; import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -53,7 +54,7 @@ public interface ReactiveSetCommands { private List values; - private SAddCommand(ByteBuffer key, List values) { + private SAddCommand(@Nullable ByteBuffer key, List values) { super(key); @@ -157,7 +158,7 @@ public interface ReactiveSetCommands { private final List values; - private SRemCommand(ByteBuffer key, List values) { + private SRemCommand(@Nullable ByteBuffer key, List values) { super(key); @@ -204,7 +205,7 @@ public interface ReactiveSetCommands { } /** - * @return + * @return never {@literal null}. */ public List getValues() { return values; @@ -261,7 +262,7 @@ public interface ReactiveSetCommands { private final long count; - private SPopCommand(ByteBuffer key, long count) { + private SPopCommand(@Nullable ByteBuffer key, long count) { super(key); this.count = count; @@ -358,10 +359,10 @@ public interface ReactiveSetCommands { */ class SMoveCommand extends KeyCommand { - private final ByteBuffer destination; + private final @Nullable ByteBuffer destination; private final ByteBuffer value; - private SMoveCommand(ByteBuffer key, ByteBuffer destination, ByteBuffer value) { + private SMoveCommand(@Nullable ByteBuffer key, @Nullable ByteBuffer destination, ByteBuffer value) { super(key); this.destination = destination; @@ -409,14 +410,15 @@ public interface ReactiveSetCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getDestination() { return destination; } /** - * @return + * @return never {@literal null}. */ public ByteBuffer getValue() { return value; @@ -484,7 +486,7 @@ public interface ReactiveSetCommands { private final ByteBuffer value; - private SIsMemberCommand(ByteBuffer key, ByteBuffer value) { + private SIsMemberCommand(@Nullable ByteBuffer key, ByteBuffer value) { super(key); @@ -577,10 +579,12 @@ public interface ReactiveSetCommands { return new SInterCommand(new ArrayList<>(keys)); } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.ReactiveRedisConnection.Command#getKey() */ @Override + @Nullable public ByteBuffer getKey() { return null; } @@ -626,7 +630,7 @@ public interface ReactiveSetCommands { private final List keys; - private SInterStoreCommand(ByteBuffer key, List keys) { + private SInterStoreCommand(@Nullable ByteBuffer key, List keys) { super(key); @@ -721,10 +725,12 @@ public interface ReactiveSetCommands { return new SUnionCommand(new ArrayList<>(keys)); } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.ReactiveRedisConnection.Command#getKey() */ @Override + @Nullable public ByteBuffer getKey() { return null; } @@ -770,7 +776,7 @@ public interface ReactiveSetCommands { private final List keys; - private SUnionStoreCommand(ByteBuffer key, List keys) { + private SUnionStoreCommand(@Nullable ByteBuffer key, List keys) { super(key); @@ -865,10 +871,12 @@ public interface ReactiveSetCommands { return new SDiffCommand(new ArrayList<>(keys)); } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.ReactiveRedisConnection.Command#getKey() */ @Override + @Nullable public ByteBuffer getKey() { return null; } @@ -914,7 +922,7 @@ public interface ReactiveSetCommands { private final List keys; - private SDiffStoreCommand(ByteBuffer key, List keys) { + private SDiffStoreCommand(@Nullable ByteBuffer key, List keys) { super(key); @@ -1013,9 +1021,9 @@ public interface ReactiveSetCommands { */ class SRandMembersCommand extends KeyCommand { - private final Long count; + private final @Nullable Long count; - private SRandMembersCommand(ByteBuffer key, Long count) { + private SRandMembersCommand(@Nullable ByteBuffer key, @Nullable Long count) { super(key); this.count = count; 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 0c1846eb4..ee680f816 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveStringCommands.java @@ -21,6 +21,7 @@ import reactor.core.publisher.Mono; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -38,6 +39,7 @@ import org.springframework.data.redis.connection.ReactiveRedisConnection.RangeCo import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.core.types.Expiration; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -57,11 +59,12 @@ public interface ReactiveStringCommands { */ class SetCommand extends KeyCommand { - private ByteBuffer value; + private @Nullable ByteBuffer value; private Expiration expiration; private SetOption option; - private SetCommand(ByteBuffer key, ByteBuffer value, Expiration expiration, SetOption option) { + private SetCommand(ByteBuffer key, @Nullable ByteBuffer value, @Nullable Expiration expiration, + @Nullable SetOption option) { super(key); @@ -125,6 +128,7 @@ public interface ReactiveStringCommands { /** * @return */ + @Nullable public ByteBuffer getValue() { return value; } @@ -358,10 +362,12 @@ public interface ReactiveStringCommands { this.keyValuePairs = keyValuePairs; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.ReactiveRedisConnection.Command#getKey() */ @Override + @Nullable public ByteBuffer getKey() { return null; } @@ -443,9 +449,9 @@ public interface ReactiveStringCommands { */ class AppendCommand extends KeyCommand { - private ByteBuffer value; + private @Nullable ByteBuffer value; - private AppendCommand(ByteBuffer key, ByteBuffer value) { + private AppendCommand(ByteBuffer key, @Nullable ByteBuffer value) { super(key); this.value = value; @@ -479,8 +485,9 @@ public interface ReactiveStringCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getValue() { return value; } @@ -546,10 +553,10 @@ public interface ReactiveStringCommands { */ class SetRangeCommand extends KeyCommand { - private ByteBuffer value; - private Long offset; + private @Nullable ByteBuffer value; + private @Nullable Long offset; - private SetRangeCommand(ByteBuffer key, ByteBuffer value, Long offset) { + private SetRangeCommand(ByteBuffer key, @Nullable ByteBuffer value, @Nullable Long offset) { super(key); this.value = value; @@ -593,15 +600,17 @@ public interface ReactiveStringCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getValue() { return value; } /** - * @return + * @return can be {@literal null}. */ + @Nullable public Long getOffset() { return offset; } @@ -643,9 +652,9 @@ public interface ReactiveStringCommands { */ class GetBitCommand extends KeyCommand { - private Long offset; + private @Nullable Long offset; - private GetBitCommand(ByteBuffer key, Long offset) { + private GetBitCommand(ByteBuffer key, @Nullable Long offset) { super(key); @@ -676,8 +685,9 @@ public interface ReactiveStringCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public Long getOffset() { return offset; } @@ -715,7 +725,7 @@ public interface ReactiveStringCommands { */ class SetBitCommand extends KeyCommand { - private Long offset; + private @Nullable Long offset; private boolean value; private SetBitCommand(ByteBuffer key, Long offset, boolean value) { @@ -760,14 +770,15 @@ public interface ReactiveStringCommands { } /** - * @return + * @return can be {@literal null}. */ + @Nullable public Long getOffset() { return offset; } /** - * @return + * @return never {@literal null}. */ public boolean getValue() { return value; @@ -825,7 +836,7 @@ public interface ReactiveStringCommands { Assert.notNull(key, "Key must not be null!"); - return new BitCountCommand(key, null); + return new BitCountCommand(key, Range.unbounded()); } /** @@ -901,9 +912,9 @@ public interface ReactiveStringCommands { private List keys; private BitOperation bitOp; - private ByteBuffer destinationKey; + private @Nullable ByteBuffer destinationKey; - private BitOpCommand(List keys, BitOperation bitOp, ByteBuffer destinationKey) { + private BitOpCommand(List keys, BitOperation bitOp, @Nullable ByteBuffer destinationKey) { this.keys = keys; this.bitOp = bitOp; @@ -920,7 +931,7 @@ public interface ReactiveStringCommands { Assert.notNull(bitOp, "BitOperation must not be null!"); - return new BitOpCommand(null, bitOp, null); + return new BitOpCommand(Collections.emptyList(), bitOp, null); } /** @@ -952,22 +963,23 @@ public interface ReactiveStringCommands { } /** - * @return + * @return never {@literal null}. */ public BitOperation getBitOp() { return bitOp; } /** - * @return + * @return never {@literal null}. */ public List getKeys() { return keys; } /** - * @return + * @return can be {@literal null}. */ + @Nullable public ByteBuffer getDestinationKey() { return destinationKey; } diff --git a/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java index ce2d7e5eb..ea8d68a19 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/ReactiveZSetCommands.java @@ -35,6 +35,7 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Aggregate; import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.util.ByteUtils; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -59,7 +60,8 @@ public interface ReactiveZSetCommands { private final boolean returnTotalChanged; private final boolean incr; - private ZAddCommand(ByteBuffer key, List tuples, boolean upsert, boolean returnTotalChanged, boolean incr) { + private ZAddCommand(@Nullable ByteBuffer key, List tuples, boolean upsert, boolean returnTotalChanged, + boolean incr) { super(key); @@ -232,7 +234,7 @@ public interface ReactiveZSetCommands { private final List values; - private ZRemCommand(ByteBuffer key, List values) { + private ZRemCommand(@Nullable ByteBuffer key, List values) { super(key); @@ -335,9 +337,9 @@ public interface ReactiveZSetCommands { class ZIncrByCommand extends KeyCommand { private final ByteBuffer value; - private final Number increment; + private final @Nullable Number increment; - private ZIncrByCommand(ByteBuffer key, ByteBuffer value, Number increment) { + private ZIncrByCommand(@Nullable ByteBuffer key, ByteBuffer value, @Nullable Number increment) { super(key); @@ -386,15 +388,16 @@ public interface ReactiveZSetCommands { } /** - * @return + * @return never {@literal null}. */ public ByteBuffer getValue() { return value; } /** - * @return + * @return can be {@literal null}. */ + @Nullable public Number getIncrement() { return increment; } @@ -441,7 +444,7 @@ public interface ReactiveZSetCommands { private final ByteBuffer value; private final Direction direction; - private ZRankCommand(ByteBuffer key, ByteBuffer value, Direction direction) { + private ZRankCommand(@Nullable ByteBuffer key, ByteBuffer value, Direction direction) { super(key); @@ -561,7 +564,7 @@ public interface ReactiveZSetCommands { private final boolean withScores; private final Direction direction; - private ZRangeCommand(ByteBuffer key, Range range, Direction direction, boolean withScores) { + private ZRangeCommand(@Nullable ByteBuffer key, Range range, Direction direction, boolean withScores) { super(key); @@ -730,10 +733,10 @@ public interface ReactiveZSetCommands { private final Range range; private final boolean withScores; private final Direction direction; - private final Limit limit; + private final @Nullable Limit limit; - private ZRangeByScoreCommand(ByteBuffer key, Range range, Direction direction, boolean withScores, - Limit limit) { + private ZRangeByScoreCommand(@Nullable ByteBuffer key, Range range, Direction direction, boolean withScores, + @Nullable Limit limit) { super(key); @@ -797,10 +800,12 @@ public interface ReactiveZSetCommands { /** * Applies the {@link Limit}. Constructs a new command instance with all previously configured properties. * - * @param limit can be {@literal null}. + * @param limit must not be {@literal null}. * @return a new {@link ZRangeByScoreCommand} with {@link Limit} applied. */ public ZRangeByScoreCommand limitTo(Limit limit) { + + Assert.notNull(limit, "Limit must not be null!"); return new ZRangeByScoreCommand(getKey(), range, direction, withScores, limit); } @@ -856,7 +861,7 @@ public interface ReactiveZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param limit can be {@literal null}. + * @param limit must not be {@literal null}. * @return * @see Redis Documentation: ZRANGEBYSCORE */ @@ -864,6 +869,7 @@ public interface ReactiveZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); + Assert.notNull(limit, "Limit must not be null!"); return zRangeByScore(Mono.just(ZRangeByScoreCommand.scoresWithin(range).from(key).limitTo(limit))) // .flatMap(CommandResponse::getOutput) // @@ -892,7 +898,7 @@ public interface ReactiveZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param limit can be {@literal null}. + * @param limit must not be {@literal null}. * @return * @see Redis Documentation: ZRANGEBYSCORE */ @@ -900,6 +906,7 @@ public interface ReactiveZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); + Assert.notNull(limit, "Limit must not be null!"); return zRangeByScore(Mono.just(ZRangeByScoreCommand.scoresWithin(range).withScores().from(key).limitTo(limit))) .flatMap(CommandResponse::getOutput); @@ -927,7 +934,7 @@ public interface ReactiveZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param limit can be {@literal null}. + * @param limit must not be {@literal null}. * @return * @see Redis Documentation: ZREVRANGEBYSCORE */ @@ -935,6 +942,7 @@ public interface ReactiveZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); + Assert.notNull(limit, "Limit must not be null!"); return zRangeByScore(Mono.just(ZRangeByScoreCommand.reverseScoresWithin(range).from(key).limitTo(limit))) // .flatMap(CommandResponse::getOutput) // @@ -963,7 +971,7 @@ public interface ReactiveZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param limit can be {@literal null}. + * @param limit must not be {@literal null}. * @return * @see Redis Documentation: ZREVRANGEBYSCORE */ @@ -971,6 +979,7 @@ public interface ReactiveZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); + Assert.notNull(limit, "Limit must not be null!"); return zRangeByScore( Mono.just(ZRangeByScoreCommand.reverseScoresWithin(range).withScores().from(key).limitTo(limit))) @@ -997,7 +1006,7 @@ public interface ReactiveZSetCommands { private final Range range; - private ZCountCommand(ByteBuffer key, Range range) { + private ZCountCommand(@Nullable ByteBuffer key, Range range) { super(key); this.range = range; @@ -1099,7 +1108,7 @@ public interface ReactiveZSetCommands { private final ByteBuffer value; - private ZScoreCommand(ByteBuffer key, ByteBuffer value) { + private ZScoreCommand(@Nullable ByteBuffer key, ByteBuffer value) { super(key); this.value = value; @@ -1250,7 +1259,7 @@ public interface ReactiveZSetCommands { private final Range range; - private ZRemRangeByScoreCommand(ByteBuffer key, Range range) { + private ZRemRangeByScoreCommand(@Nullable ByteBuffer key, Range range) { super(key); this.range = range; @@ -1323,9 +1332,10 @@ public interface ReactiveZSetCommands { private final List sourceKeys; private final List weights; - private final Aggregate aggregateFunction; + private final @Nullable Aggregate aggregateFunction; - private ZUnionStoreCommand(ByteBuffer key, List sourceKeys, List weights, Aggregate aggregate) { + private ZUnionStoreCommand(@Nullable ByteBuffer key, List sourceKeys, List weights, + @Nullable Aggregate aggregate) { super(key); this.sourceKeys = sourceKeys; @@ -1343,7 +1353,7 @@ public interface ReactiveZSetCommands { Assert.notNull(keys, "Keys must not be null!"); - return new ZUnionStoreCommand(null, new ArrayList<>(keys), null, null); + return new ZUnionStoreCommand(null, new ArrayList<>(keys), Collections.emptyList(), null); } /** @@ -1363,7 +1373,8 @@ public interface ReactiveZSetCommands { * @param aggregateFunction can be {@literal null}. * @return a new {@link ZUnionStoreCommand} with {@link Aggregate} applied. */ - public ZUnionStoreCommand aggregateUsing(Aggregate aggregateFunction) { + public ZUnionStoreCommand aggregateUsing(@Nullable Aggregate aggregateFunction) { + return new ZUnionStoreCommand(getKey(), sourceKeys, weights, aggregateFunction); } @@ -1382,21 +1393,21 @@ public interface ReactiveZSetCommands { } /** - * @return + * @return never {@literal null}. */ public List getSourceKeys() { return sourceKeys; } /** - * @return + * @return never {@literal null}. */ public List getWeights() { - return weights == null ? Collections.emptyList() : weights; + return weights; } /** - * @return + * @return never {@literal null}. */ public Optional getAggregateFunction() { return Optional.ofNullable(aggregateFunction); @@ -1412,7 +1423,7 @@ public interface ReactiveZSetCommands { * @see Redis Documentation: ZUNIONSTORE */ default Mono zUnionStore(ByteBuffer destinationKey, List sets) { - return zUnionStore(destinationKey, sets, null); + return zUnionStore(destinationKey, sets, Collections.emptyList()); } /** @@ -1421,7 +1432,7 @@ public interface ReactiveZSetCommands { * * @param destinationKey must not be {@literal null}. * @param sets must not be {@literal null}. - * @param weights can be {@literal null}. + * @param weights must not be {@literal null}. * @return * @see Redis Documentation: ZUNIONSTORE */ @@ -1441,7 +1452,7 @@ public interface ReactiveZSetCommands { * @see Redis Documentation: ZUNIONSTORE */ default Mono zUnionStore(ByteBuffer destinationKey, List sets, List weights, - Aggregate aggregateFunction) { + @Nullable Aggregate aggregateFunction) { Assert.notNull(destinationKey, "DestinationKey must not be null!"); Assert.notNull(sets, "Sets must not be null!"); @@ -1471,9 +1482,10 @@ public interface ReactiveZSetCommands { private final List sourceKeys; private final List weights; - private final Aggregate aggregateFunction; + private final @Nullable Aggregate aggregateFunction; - private ZInterStoreCommand(ByteBuffer key, List sourceKeys, List weights, Aggregate aggregate) { + private ZInterStoreCommand(ByteBuffer key, List sourceKeys, List weights, + @Nullable Aggregate aggregate) { super(key); this.sourceKeys = sourceKeys; @@ -1491,7 +1503,7 @@ public interface ReactiveZSetCommands { Assert.notNull(keys, "Keys must not be null!"); - return new ZInterStoreCommand(null, new ArrayList<>(keys), null, null); + return new ZInterStoreCommand(null, new ArrayList<>(keys), Collections.emptyList(), null); } /** @@ -1512,7 +1524,8 @@ public interface ReactiveZSetCommands { * @param aggregateFunction can be {@literal null}. * @return a new {@link ZInterStoreCommand} with {@link Aggregate} applied. */ - public ZInterStoreCommand aggregateUsing(Aggregate aggregateFunction) { + public ZInterStoreCommand aggregateUsing(@Nullable Aggregate aggregateFunction) { + return new ZInterStoreCommand(getKey(), sourceKeys, weights, aggregateFunction); } @@ -1531,21 +1544,21 @@ public interface ReactiveZSetCommands { } /** - * @return + * @return never {@literal null}. */ public List getSourceKeys() { return sourceKeys; } /** - * @return + * @return never {@literal null}. */ public List getWeights() { - return weights == null ? Collections.emptyList() : weights; + return weights; } /** - * @return + * @return never {@literal null}.ø */ public Optional getAggregateFunction() { return Optional.ofNullable(aggregateFunction); @@ -1561,7 +1574,7 @@ public interface ReactiveZSetCommands { * @see Redis Documentation: ZINTERSTORE */ default Mono zInterStore(ByteBuffer destinationKey, List sets) { - return zInterStore(destinationKey, sets, null); + return zInterStore(destinationKey, sets, Collections.emptyList()); } /** @@ -1570,7 +1583,7 @@ public interface ReactiveZSetCommands { * * @param destinationKey must not be {@literal null}. * @param sets must not be {@literal null}. - * @param weights can be {@literal null}. + * @param weights must not be {@literal null}. * @return * @see Redis Documentation: ZINTERSTORE */ @@ -1584,13 +1597,13 @@ public interface ReactiveZSetCommands { * * @param destinationKey must not be {@literal null}. * @param sets must not be {@literal null}. - * @param weights can be {@literal null}. + * @param weights must not be {@literal null}. * @param aggregateFunction can be {@literal null}. * @return * @see Redis Documentation: ZINTERSTORE */ default Mono zInterStore(ByteBuffer destinationKey, List sets, List weights, - Aggregate aggregateFunction) { + @Nullable Aggregate aggregateFunction) { Assert.notNull(destinationKey, "DestinationKey must not be null!"); Assert.notNull(sets, "Sets must not be null!"); @@ -1623,7 +1636,7 @@ public interface ReactiveZSetCommands { private final Direction direction; private final Limit limit; - private ZRangeByLexCommand(ByteBuffer key, Range range, Direction direction, Limit limit) { + private ZRangeByLexCommand(@Nullable ByteBuffer key, Range range, Direction direction, Limit limit) { super(key); this.range = range; @@ -1642,7 +1655,7 @@ public interface ReactiveZSetCommands { Assert.notNull(range, "Range must not be null!"); - return new ZRangeByLexCommand(null, range, Direction.ASC, null); + return new ZRangeByLexCommand(null, range, Direction.ASC, Limit.unlimited()); } /** @@ -1656,7 +1669,7 @@ public interface ReactiveZSetCommands { Assert.notNull(range, "Range must not be null!"); - return new ZRangeByLexCommand(null, range, Direction.DESC, null); + return new ZRangeByLexCommand(null, range, Direction.DESC, Limit.unlimited()); } /** @@ -1675,10 +1688,12 @@ public interface ReactiveZSetCommands { /** * Applies the {@link Limit}. Constructs a new command instance with all previously configured properties. * - * @param limit can be {@literal null}. + * @param limit must not be {@literal null}. * @return a new {@link ZRangeByLexCommand} with {@link Limit} applied. */ public ZRangeByLexCommand limitTo(Limit limit) { + + Assert.notNull(limit, "Limit must not be null!"); return new ZRangeByLexCommand(getKey(), range, direction, limit); } @@ -1713,7 +1728,7 @@ public interface ReactiveZSetCommands { * @see Redis Documentation: ZRANGEBYLEX */ default Flux zRangeByLex(ByteBuffer key, Range range) { - return zRangeByLex(key, range, null); + return zRangeByLex(key, range, Limit.unlimited()); } /** @@ -1744,7 +1759,7 @@ public interface ReactiveZSetCommands { * @see Redis Documentation: ZREVRANGEBYLEX */ default Flux zRevRangeByLex(ByteBuffer key, Range range) { - return zRevRangeByLex(key, range, null); + return zRevRangeByLex(key, range, Limit.unlimited()); } /** @@ -1753,7 +1768,7 @@ public interface ReactiveZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param limit can be {@literal null}. + * @param limit must not be {@literal null}. * @return * @see Redis Documentation: ZREVRANGEBYLEX */ @@ -1761,6 +1776,7 @@ public interface ReactiveZSetCommands { Assert.notNull(key, "Key must not be null!"); Assert.notNull(range, "Range must not be null!"); + Assert.notNull(limit, "Limit must not be null!"); return zRangeByLex(Mono.just(ZRangeByLexCommand.reverseStringsWithin(range).from(key).limitTo(limit))) .flatMap(CommandResponse::getOutput); diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterCommands.java index 061068f5f..826ed7868 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisClusterCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterCommands.java @@ -179,7 +179,7 @@ public interface RedisClusterCommands { */ void clusterReplicate(RedisClusterNode master, RedisClusterNode slave); - public enum AddSlots { + enum AddSlots { MIGRATING, IMPORTING, STABLE, NODE } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterConfiguration.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterConfiguration.java index 8736d22a4..2783bd02e 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisClusterConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterConfiguration.java @@ -27,6 +27,7 @@ import java.util.Set; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.NumberUtils; import org.springframework.util.StringUtils; @@ -46,7 +47,7 @@ public class RedisClusterConfiguration { private static final String REDIS_CLUSTER_MAX_REDIRECTS_CONFIG_PROPERTY = "spring.redis.cluster.max-redirects"; private Set clusterNodes; - private Integer maxRedirects; + private @Nullable Integer maxRedirects; private RedisPassword password = RedisPassword.none(); /** @@ -213,7 +214,6 @@ public class RedisClusterConfiguration { /** * @param clusterHostAndPorts must not be {@literal null} or empty. * @param redirects the max number of redirects to follow. - * @param password can be {@literal null} or empty. * @return cluster config map with properties. */ private static Map asMap(Collection clusterHostAndPorts, int redirects) { diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java index 765268fe3..7af3f274e 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterConnection.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,6 +17,8 @@ package org.springframework.data.redis.connection; import java.util.Set; +import org.springframework.lang.Nullable; + /** * {@link RedisClusterConnection} allows sending commands to dedicated nodes within the cluster. A * {@link RedisClusterNode} can be obtained from {@link #clusterGetNodes()} or it can be constructed using either @@ -31,24 +33,27 @@ public interface RedisClusterConnection extends RedisConnection, RedisClusterCom /** * @param node must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see RedisConnectionCommands#ping() */ + @Nullable String ping(RedisClusterNode node); /** * @param node must not be {@literal null}. * @param pattern must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see RedisKeyCommands#keys(byte[]) */ + @Nullable Set keys(RedisClusterNode node, byte[] pattern); /** * @param node must not be {@literal null}. - * @return + * @return {@literal null} when no keys stored at node or when used in pipeline / transaction. * @see RedisKeyCommands#randomKey() */ + @Nullable byte[] randomKey(RedisClusterNode node); /** diff --git a/src/main/java/org/springframework/data/redis/connection/RedisClusterNode.java b/src/main/java/org/springframework/data/redis/connection/RedisClusterNode.java index f66abb30c..789aef656 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisClusterNode.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisClusterNode.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -33,11 +34,13 @@ import org.springframework.util.CollectionUtils; public class RedisClusterNode extends RedisNode { private SlotRange slotRange; - private LinkState linkState; + private @Nullable LinkState linkState; private Set flags; protected RedisClusterNode() { + super(); + flags = Collections.emptySet(); } /** @@ -47,7 +50,7 @@ public class RedisClusterNode extends RedisNode { * @param port */ public RedisClusterNode(String host, int port) { - this(host, port, new SlotRange(Collections. emptySet())); + this(host, port, SlotRange.empty()); } /** @@ -57,7 +60,7 @@ public class RedisClusterNode extends RedisNode { */ public RedisClusterNode(String id) { - this(new SlotRange(Collections. emptySet())); + this(SlotRange.empty()); Assert.notNull(id, "Id must not be null!"); this.id = id; } @@ -67,23 +70,34 @@ public class RedisClusterNode extends RedisNode { * * @param host must not be {@literal null}. * @param port - * @param slotRange can be {@literal null}. + * @param slotRange must not be {@literal null}. */ public RedisClusterNode(String host, int port, SlotRange slotRange) { super(host, port); - this.slotRange = slotRange != null ? slotRange : new SlotRange(Collections. emptySet()); + + Assert.notNull(slotRange, "SlotRange must not be null!"); + this.slotRange = slotRange; } /** * Creates new {@link RedisClusterNode} with given {@link SlotRange}. * - * @param slotRange can be {@literal null}. + * @param slotRange must not be {@literal null}. */ public RedisClusterNode(SlotRange slotRange) { super(); - this.slotRange = slotRange != null ? slotRange : new SlotRange(Collections. emptySet()); + + Assert.notNull(slotRange, "SlotRange must not be null!"); + + this.slotRange = slotRange; + } + + { + if (flags == null) { + flags = Collections.emptySet(); + } } /** @@ -104,8 +118,9 @@ public class RedisClusterNode extends RedisNode { } /** - * @return + * @return can be {@literal null} */ + @Nullable public LinkState getLinkState() { return linkState; } @@ -121,7 +136,7 @@ public class RedisClusterNode extends RedisNode { * @return never {@literal null}. */ public Set getFlags() { - return flags == null ? Collections. emptySet() : flags; + return flags == null ? Collections.emptySet() : flags; } /** @@ -177,8 +192,7 @@ public class RedisClusterNode extends RedisNode { } public SlotRange(Collection range) { - this.range = CollectionUtils.isEmpty(range) ? Collections. emptySet() - : new LinkedHashSet<>(range); + this.range = CollectionUtils.isEmpty(range) ? Collections.emptySet() : new LinkedHashSet<>(range); } @Override @@ -212,13 +226,17 @@ public class RedisClusterNode extends RedisNode { return slots; } + + public static SlotRange empty() { + return new SlotRange(Collections.emptySet()); + } } /** * @author Christoph Strobl * @since 1.7 */ - public static enum LinkState { + public enum LinkState { CONNECTED, DISCONNECTED } @@ -251,12 +269,12 @@ public class RedisClusterNode extends RedisNode { */ public static class RedisClusterNodeBuilder extends RedisNodeBuilder { - Set flags; - LinkState linkState; + @Nullable Set flags; + @Nullable LinkState linkState; SlotRange slotRange; public RedisClusterNodeBuilder() { - + this.slotRange = SlotRange.empty(); } /* diff --git a/src/main/java/org/springframework/data/redis/connection/RedisCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisCommands.java index f0b3020e4..071b9f671 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisCommands.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2016 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. @@ -16,6 +16,8 @@ package org.springframework.data.redis.connection; +import org.springframework.lang.Nullable; + /** * Interface for the commands supported by Redis. * @@ -30,10 +32,11 @@ public interface RedisCommands extends RedisKeyCommands, RedisStringCommands, Re * 'Native' or 'raw' execution of the given command along-side the given arguments. The command is executed as is, * with as little 'interpretation' as possible - it is up to the caller to take care of any processing of arguments or * the result. - * - * @param command Command to execute - * @param args Possible command arguments (may be null) - * @return execution result. + * + * @param command Command to execute. must not be {@literal null}. + * @param args Possible command arguments (may be empty). + * @return execution result. Can be {@literal null}. */ + @Nullable Object execute(String command, byte[]... args); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisConnectionCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisConnectionCommands.java index d96fd2632..5d112872a 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisConnectionCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisConnectionCommands.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.connection; +import org.springframework.lang.Nullable; + /** * Connection-specific commands supported by Redis. * @@ -36,16 +38,18 @@ public interface RedisConnectionCommands { * Returns {@code message} via server roundtrip. * * @param message the message to echo. - * @return + * @return the message or {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ECHO */ + @Nullable byte[] echo(byte[] message); /** * Test connection. * - * @return Server response message - usually {@literal PONG}. + * @return Server response message - usually {@literal PONG}. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: PING */ + @Nullable String ping(); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisGeoCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisGeoCommands.java index 99e7de7bd..fd5333cd1 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisGeoCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisGeoCommands.java @@ -29,6 +29,7 @@ import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Metric; import org.springframework.data.geo.Point; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -47,9 +48,10 @@ public interface RedisGeoCommands { * @param key must not be {@literal null}. * @param point must not be {@literal null}. * @param member must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD */ + @Nullable Long geoAdd(byte[] key, Point point, byte[] member); /** @@ -57,9 +59,10 @@ public interface RedisGeoCommands { * * @param key must not be {@literal null}. * @param location must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD */ + @Nullable default Long geoAdd(byte[] key, GeoLocation location) { Assert.notNull(key, "Key must not be null!"); @@ -73,9 +76,10 @@ public interface RedisGeoCommands { * * @param key must not be {@literal null}. * @param memberCoordinateMap must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD */ + @Nullable Long geoAdd(byte[] key, Map memberCoordinateMap); /** @@ -83,9 +87,10 @@ public interface RedisGeoCommands { * * @param key must not be {@literal null}. * @param locations must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD */ + @Nullable Long geoAdd(byte[] key, Iterable> locations); /** @@ -94,9 +99,10 @@ public interface RedisGeoCommands { * @param key must not be {@literal null}. * @param member1 must not be {@literal null}. * @param member2 must not be {@literal null}. - * @return can be {@literal null}. + * @return can be {@literal null}. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEODIST */ + @Nullable Distance geoDist(byte[] key, byte[] member1, byte[] member2); /** @@ -106,9 +112,10 @@ public interface RedisGeoCommands { * @param member1 must not be {@literal null}. * @param member2 must not be {@literal null}. * @param metric must not be {@literal null}. - * @return can be {@literal null}. + * @return can be {@literal null}. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEODIST */ + @Nullable Distance geoDist(byte[] key, byte[] member1, byte[] member2, Metric metric); /** @@ -116,9 +123,10 @@ public interface RedisGeoCommands { * * @param key must not be {@literal null}. * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return empty list when key or members do not exists. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOHASH */ + @Nullable List geoHash(byte[] key, byte[]... members); /** @@ -126,9 +134,10 @@ public interface RedisGeoCommands { * * @param key must not be {@literal null}. * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return empty {@link List} when key of members do not exist. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOPOS */ + @Nullable List geoPos(byte[] key, byte[]... members); /** @@ -136,9 +145,10 @@ public interface RedisGeoCommands { * * @param key must not be {@literal null}. * @param within must not be {@literal null}. - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEORADIUS */ + @Nullable GeoResults> geoRadius(byte[] key, Circle within); /** @@ -147,9 +157,10 @@ public interface RedisGeoCommands { * @param key must not be {@literal null}. * @param within must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEORADIUS */ + @Nullable GeoResults> geoRadius(byte[] key, Circle within, GeoRadiusCommandArgs args); /** @@ -159,9 +170,10 @@ public interface RedisGeoCommands { * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @param radius - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEORADIUSBYMEMBER */ + @Nullable default GeoResults> geoRadiusByMember(byte[] key, byte[] member, double radius) { return geoRadiusByMember(key, member, new Distance(radius, DistanceUnit.METERS)); } @@ -173,9 +185,10 @@ public interface RedisGeoCommands { * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @param radius must not be {@literal null}. - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction.. * @see Redis Documentation: GEORADIUSBYMEMBER */ + @Nullable GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius); /** @@ -186,9 +199,10 @@ public interface RedisGeoCommands { * @param member must not be {@literal null}. * @param radius must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEORADIUSBYMEMBER */ + @Nullable GeoResults> geoRadiusByMember(byte[] key, byte[] member, Distance radius, GeoRadiusCommandArgs args); @@ -197,9 +211,10 @@ public interface RedisGeoCommands { * * @param key must not be {@literal null}. * @param members must not be {@literal null}. - * @return Number of elements removed. + * @return Number of elements removed. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREM */ + @Nullable Long geoRemove(byte[] key, byte[]... members); /** @@ -212,8 +227,8 @@ public interface RedisGeoCommands { class GeoRadiusCommandArgs implements Cloneable { Set flags = new LinkedHashSet<>(2, 1); - Long limit; - Direction sortDirection; + @Nullable Long limit; + @Nullable Direction sortDirection; private GeoRadiusCommandArgs() {} @@ -293,6 +308,7 @@ public interface RedisGeoCommands { /** * @return can be {@literal null}. */ + @Nullable public Long getLimit() { return limit; } @@ -300,6 +316,7 @@ public interface RedisGeoCommands { /** * @return can be {@literal null}. */ + @Nullable public Direction getSortDirection() { return sortDirection; } @@ -316,7 +333,7 @@ public interface RedisGeoCommands { return limit != null; } - public static enum Flag { + public enum Flag { WITHCOORD, WITHDIST } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java index 4e533f233..d4bb421b6 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisHashCommands.java @@ -21,6 +21,7 @@ import java.util.Set; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.lang.Nullable; /** * Hash-specific commands supported by Redis. @@ -36,10 +37,11 @@ public interface RedisHashCommands { * * @param key must not be {@literal null}. * @param field must not be {@literal null}. - * @param value - * @return + * @param value must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HSET */ + @Nullable Boolean hSet(byte[] key, byte[] field, byte[] value); /** @@ -47,10 +49,11 @@ public interface RedisHashCommands { * * @param key must not be {@literal null}. * @param field must not be {@literal null}. - * @param value - * @return + * @param value must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HSETNX */ + @Nullable Boolean hSetNX(byte[] key, byte[] field, byte[] value); /** @@ -58,19 +61,21 @@ public interface RedisHashCommands { * * @param key must not be {@literal null}. * @param field must not be {@literal null}. - * @return + * @return {@literal null} when key or field do not exists or when used in pipeline / transaction. * @see Redis Documentation: HGET */ + @Nullable byte[] hGet(byte[] key, byte[] field); /** * Get values for given {@code fields} from hash at {@code key}. * * @param key must not be {@literal null}. - * @param fields must not be {@literal null}. - * @return + * @param fields must not be {@literal empty}. + * @return empty {@link List} if key or fields do not exists. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HMGET */ + @Nullable List hMGet(byte[] key, byte[]... fields); /** @@ -88,20 +93,22 @@ public interface RedisHashCommands { * @param key must not be {@literal null}. * @param field must not be {@literal null}. * @param delta - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HINCRBY */ + @Nullable Long hIncrBy(byte[] key, byte[] field, long delta); /** * Increment {@code value} of a hash {@code field} by the given {@code delta}. * * @param key must not be {@literal null}. - * @param field + * @param field must not be {@literal null}. * @param delta - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HINCRBYFLOAT */ + @Nullable Double hIncrBy(byte[] key, byte[] field, double delta); /** @@ -109,55 +116,61 @@ public interface RedisHashCommands { * * @param key must not be {@literal null}. * @param field must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HEXISTS */ + @Nullable Boolean hExists(byte[] key, byte[] field); /** * Delete given hash {@code fields}. * * @param key must not be {@literal null}. - * @param fields must not be {@literal null}. - * @return + * @param fields must not be {@literal empty}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HDEL */ + @Nullable Long hDel(byte[] key, byte[]... fields); /** * Get size of hash at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HLEN */ + @Nullable Long hLen(byte[] key); /** * Get key set (fields) of hash at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HKEYS? */ + @Nullable Set hKeys(byte[] key); /** * Get entry set (values) of hash at {@code field}. * * @param key must not be {@literal null}. - * @return + * @return empty {@link List} if key does not exist. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HVALS */ + @Nullable List hVals(byte[] key); /** * Get entire hash stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return empty {@link Map} if key does not exist or {@literal null} when used in pipeline / transaction. * @see Redis Documentation: HGETALL */ + @Nullable Map hGetAll(byte[] key); /** diff --git a/src/main/java/org/springframework/data/redis/connection/RedisHyperLogLogCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisHyperLogLogCommands.java index d05c83047..36999c1c3 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisHyperLogLogCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisHyperLogLogCommands.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.connection; +import org.springframework.lang.Nullable; + /** * {@literal HyperLogLog} specific commands supported by Redis. * @@ -29,18 +31,20 @@ public interface RedisHyperLogLogCommands { * * @param key must not be {@literal null}. * @param values must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: PFADD */ + @Nullable Long pfAdd(byte[] key, byte[]... values); /** * Return the approximated cardinality of the structures observed by the HyperLogLog at {@literal key(s)}. * * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: PFCOUNT */ + @Nullable Long pfCount(byte[]... keys); /** 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 1f372479d..809edee5a 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisKeyCommands.java @@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.lang.Nullable; /** * Key-specific commands supported by Redis. @@ -35,43 +36,47 @@ public interface RedisKeyCommands { * Determine if given {@code key} exists. * * @param key must not be {@literal null}. - * @return + * @return {@literal true} if key exists. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: EXISTS */ + @Nullable Boolean exists(byte[] key); /** * Delete given {@code keys}. * * @param keys must not be {@literal null}. - * @return The number of keys that were removed. + * @return The number of keys that were removed. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: DEL */ + @Nullable Long del(byte[]... keys); /** * Determine the type stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: TYPE */ + @Nullable DataType type(byte[] key); /** * Find all keys matching the given {@code pattern}. * * @param pattern must not be {@literal null}. - * @return + * @return empty {@link Set} if no match found. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: KEYS */ + @Nullable Set keys(byte[] pattern); /** * Use a {@link Cursor} to iterate over keys. * * @param options must not be {@literal null}. - * @return + * @return never {@literal null}. * @since 1.4 * @see Redis Documentation: SCAN */ @@ -80,9 +85,10 @@ public interface RedisKeyCommands { /** * Return a random key from the keyspace. * - * @return + * @return {@literal null} if no keys available or when used in pipeline or transaction. * @see Redis Documentation: RANDOMKEY */ + @Nullable byte[] randomKey(); /** @@ -99,9 +105,10 @@ public interface RedisKeyCommands { * * @param oldName must not be {@literal null}. * @param newName must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RENAMENX */ + @Nullable Boolean renameNX(byte[] oldName, byte[] newName); /** @@ -109,9 +116,10 @@ public interface RedisKeyCommands { * * @param key must not be {@literal null}. * @param seconds - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: EXPIRE */ + @Nullable Boolean expire(byte[] key, long seconds); /** @@ -119,9 +127,10 @@ public interface RedisKeyCommands { * * @param key must not be {@literal null}. * @param millis - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: PEXPIRE */ + @Nullable Boolean pExpire(byte[] key, long millis); /** @@ -129,9 +138,10 @@ public interface RedisKeyCommands { * * @param key must not be {@literal null}. * @param unixTime - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: EXPIREAT */ + @Nullable Boolean expireAt(byte[] key, long unixTime); /** @@ -139,18 +149,20 @@ public interface RedisKeyCommands { * * @param key must not be {@literal null}. * @param unixTimeInMillis - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: PEXPIREAT */ + @Nullable Boolean pExpireAt(byte[] key, long unixTimeInMillis); /** * Remove the expiration from given {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: PERSIST */ + @Nullable Boolean persist(byte[] key); /** @@ -158,18 +170,20 @@ public interface RedisKeyCommands { * * @param key must not be {@literal null}. * @param dbIndex - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: MOVE */ + @Nullable Boolean move(byte[] key, int dbIndex); /** * Get the time to live for {@code key} in seconds. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: TTL */ + @Nullable Long ttl(byte[] key); /** @@ -177,19 +191,21 @@ public interface RedisKeyCommands { * * @param key must not be {@literal null}. * @param timeUnit must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.8 * @see Redis Documentation: TTL */ + @Nullable Long ttl(byte[] key, TimeUnit timeUnit); /** * Get the precise time to live for {@code key} in milliseconds. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: PTTL */ + @Nullable Long pTtl(byte[] key); /** @@ -197,10 +213,11 @@ public interface RedisKeyCommands { * * @param key must not be {@literal null}. * @param timeUnit must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.8 * @see Redis Documentation: PTTL */ + @Nullable Long pTtl(byte[] key, TimeUnit timeUnit); /** @@ -208,9 +225,10 @@ public interface RedisKeyCommands { * * @param key must not be {@literal null}. * @param params must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SORT */ + @Nullable List sort(byte[] key, SortParameters params); /** @@ -219,18 +237,20 @@ public interface RedisKeyCommands { * @param key must not be {@literal null}. * @param params must not be {@literal null}. * @param storeKey must not be {@literal null}. - * @return number of values. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SORT */ + @Nullable Long sort(byte[] key, SortParameters params, byte[] storeKey); /** * Retrieve serialized version of the value stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} if key does not exist or when used in pipeline / transaction. * @see Redis Documentation: DUMP */ + @Nullable byte[] dump(byte[] key); /** 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 0f4c6fe1c..fbbe7d297 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisListCommands.java @@ -17,6 +17,8 @@ package org.springframework.data.redis.connection; import java.util.List; +import org.springframework.lang.Nullable; + /** * List-specific commands supported by Redis. * @@ -29,7 +31,7 @@ public interface RedisListCommands { /** * List insertion position. */ - public enum Position { + enum Position { BEFORE, AFTER } @@ -37,49 +39,54 @@ public interface RedisListCommands { * Append {@code values} to {@code key}. * * @param key must not be {@literal null}. - * @param values - * @return + * @param values must not be empty. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSH */ + @Nullable Long rPush(byte[] key, byte[]... values); /** * Prepend {@code values} to {@code key}. * * @param key must not be {@literal null}. - * @param values - * @return + * @param values must not be empty. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSH */ + @Nullable Long lPush(byte[] key, byte[]... values); /** * Append {@code values} to {@code key} only if the list exists. * * @param key must not be {@literal null}. - * @param value - * @return + * @param value must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSHX */ + @Nullable Long rPushX(byte[] key, byte[] value); /** * Prepend {@code values} to {@code key} only if the list exists. * * @param key must not be {@literal null}. - * @param value - * @return + * @param value must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSHX */ + @Nullable Long lPushX(byte[] key, byte[] value); /** * 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 lLen(byte[] key); /** @@ -88,9 +95,11 @@ public interface RedisListCommands { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return empty {@link List} if key does not exists or range does not contain values. {@literal null} when used in + * pipeline / transaction. * @see Redis Documentation: LRANGE */ + @Nullable List lRange(byte[] key, long start, long end); /** @@ -107,10 +116,11 @@ public interface RedisListCommands { * Get element at {@code index} form list at {@code key}. * * @param key must not be {@literal null}. - * @param index - * @return + * @param index zero based index value. Use negative number to designate elements starting at the tail. + * @return {@literal null} when index is out of range or when used in pipeline / transaction. * @see Redis Documentation: LINDEX */ + @Nullable byte[] lIndex(byte[] key, long index); /** @@ -118,11 +128,12 @@ public interface RedisListCommands { * * @param key must not be {@literal null}. * @param where must not be {@literal null}. - * @param pivot - * @param value - * @return + * @param pivot must not be {@literal null}. + * @param value must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LINSERT */ + @Nullable Long lInsert(byte[] key, Position where, byte[] pivot, byte[] value); /** @@ -141,51 +152,58 @@ public interface RedisListCommands { * @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 lRem(byte[] key, long count, byte[] value); /** * Removes and returns first element in list stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when key does not exist or used in pipeline / transaction. * @see Redis Documentation: LPOP */ + @Nullable byte[] lPop(byte[] key); /** * Removes and returns last element in list stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when key does not exist or used in pipeline / transaction. * @see Redis Documentation: RPOP */ + @Nullable byte[] rPop(byte[] key); /** * Removes and returns first element from lists stored at {@code keys}.
* Blocks connection until element available or {@code timeout} reached. * - * @param timeout + * @param timeout seconds to block. * @param keys must not be {@literal null}. - * @return + * @return empty {@link List} when no element could be popped and the timeout was reached. {@literal null} when used + * in pipeline / transaction. * @see Redis Documentation: BLPOP * @see #lPop(byte[]) */ + @Nullable List bLPop(int timeout, byte[]... keys); /** * Removes and returns last element from lists stored at {@code keys}.
* Blocks connection until element available or {@code timeout} reached. * - * @param timeout + * @param timeout seconds to block. * @param keys must not be {@literal null}. - * @return + * @return empty {@link List} when no element could be popped and the timeout was reached. {@literal null} when used + * in pipeline / transaction. * @see Redis Documentation: BRPOP * @see #rPop(byte[]) */ + @Nullable List bRPop(int timeout, byte[]... keys); /** @@ -193,22 +211,23 @@ public interface RedisListCommands { * * @param srcKey must not be {@literal null}. * @param dstKey must not be {@literal null}. - * @return + * @return can be {@literal null}. * @see Redis Documentation: RPOPLPUSH */ + @Nullable byte[] rPopLPush(byte[] srcKey, byte[] dstKey); /** - * Remove the last element from list at {@code srcKey}, append it to {@code dstKey} and return its value. - *
+ * Remove the last element from list at {@code srcKey}, append it to {@code dstKey} and return its value.
* Blocks connection until element available or {@code timeout} reached. * - * @param timeout + * @param timeout seconds to block. * @param srcKey must not be {@literal null}. * @param dstKey must not be {@literal null}. - * @return + * @return can be {@literal null}. * @see Redis Documentation: BRPOPLPUSH * @see #rPopLPush(byte[], byte[]) */ + @Nullable byte[] bRPopLPush(int timeout, byte[] srcKey, byte[] dstKey); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisNode.java b/src/main/java/org/springframework/data/redis/connection/RedisNode.java index b4f47b941..9883008d4 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisNode.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisNode.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.connection; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -26,12 +27,12 @@ import org.springframework.util.ObjectUtils; */ public class RedisNode implements NamedNode { - String id; - String name; - String host; + @Nullable String id; + @Nullable String name; + @Nullable String host; int port; - NodeType type; - String masterId; + @Nullable NodeType type; + @Nullable String masterId; /** * Creates a new {@link RedisNode} with the given {@code host}, {@code port}. @@ -49,10 +50,18 @@ public class RedisNode implements NamedNode { protected RedisNode() {} + /** + * @return can be {@literal null}. + */ + @Nullable public String getHost() { return host; } + /** + * @return can be {@literal null}. + */ + @Nullable public Integer getPort() { return port; } @@ -62,6 +71,7 @@ public class RedisNode implements NamedNode { } @Override + @Nullable public String getName() { return this.name; } @@ -71,23 +81,24 @@ public class RedisNode implements NamedNode { } /** - * @return + * @return can be {@literal null}. * @since 1.7 */ + @Nullable public String getMasterId() { return masterId; } /** - * @return + * @return can be {@literal null}. * @since 1.7 */ + @Nullable public String getId() { return id; } /** - * * @param id * @since 1.7 */ @@ -96,9 +107,10 @@ public class RedisNode implements NamedNode { } /** - * @return + * @return can be {@literal null}. * @since 1.7 */ + @Nullable public NodeType getType() { return type; } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisPipelineException.java b/src/main/java/org/springframework/data/redis/connection/RedisPipelineException.java index 324b79e83..357437b94 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisPipelineException.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisPipelineException.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.List; import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.lang.Nullable; /** * Exception thrown when executing/closing a pipeline that contains one or multiple invalid/incorrect statements. The @@ -41,7 +42,7 @@ public class RedisPipelineException extends InvalidDataAccessResourceUsageExcept * @param cause the cause * @param pipelineResult the pipeline result */ - public RedisPipelineException(String msg, Throwable cause, List pipelineResult) { + public RedisPipelineException(@Nullable String msg, @Nullable Throwable cause, List pipelineResult) { super(msg, cause); results = Collections.unmodifiableList(pipelineResult); } 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 a435c754b..440e1f742 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisPubSubCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisPubSubCommands.java @@ -15,34 +15,38 @@ */ package org.springframework.data.redis.connection; +import org.springframework.lang.Nullable; + /** * PubSub-specific Redis commands. * * @author Costin Leau * @author Mark Paluch + * @author Christoph Strobl */ public interface RedisPubSubCommands { /** * Indicates whether the current connection is subscribed (to at least one channel) or not. - * + * * @return true if the connection is subscribed, false otherwise */ boolean isSubscribed(); /** * Returns the current subscription for this connection or null if the connection is not subscribed. - * - * @return the current subscription, null if none is available + * + * @return the current subscription, {@literal null} if none is available. */ + @Nullable Subscription getSubscription(); /** * Publishes the given message to the given channel. - * - * @param channel the channel to publish to, must not be {@literal null}. - * @param message message to publish - * @return the number of clients that received the message + * + * @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. * @see Redis Documentation: PUBLISH */ Long publish(byte[] channel, byte[] message); @@ -52,7 +56,7 @@ public interface RedisPubSubCommands { * subscribe to other channels or unsubscribe. No other commands are accepted until the connection is unsubscribed. *

* Note that this operation is blocking and the current thread starts waiting for new messages immediately. - * + * * @param listener message listener, must not be {@literal null}. * @param channels channel names, must not be {@literal null}. * @see Redis Documentation: SUBSCRIBE @@ -65,7 +69,7 @@ public interface RedisPubSubCommands { * connection is unsubscribed. *

* Note that this operation is blocking and the current thread starts waiting for new messages immediately. - * + * * @param listener message listener, must not be {@literal null}. * @param patterns channel name patterns, must not be {@literal null}. * @see Redis Documentation: PSUBSCRIBE diff --git a/src/main/java/org/springframework/data/redis/connection/RedisScriptingCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisScriptingCommands.java index 48614c58a..0cf0f6407 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisScriptingCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisScriptingCommands.java @@ -17,9 +17,11 @@ package org.springframework.data.redis.connection; import java.util.List; +import org.springframework.lang.Nullable; + /** * Scripting commands. - * + * * @author Costin Leau * @author Christoph Strobl * @author David Liu @@ -46,18 +48,21 @@ public interface RedisScriptingCommands { * Execute the script by calling {@link #evalSha(byte[], ReturnType, int, byte[]...)}. * * @param script must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SCRIPT LOAD */ + @Nullable String scriptLoad(byte[] script); /** * Check if given {@code scriptShas} exist in script cache. * * @param scriptShas - * @return one entry per given scriptSha in returned list. + * @return one entry per given scriptSha in returned {@link List} or {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: SCRIPT EXISTS */ + @Nullable List scriptExists(String... scriptShas); /** @@ -67,9 +72,10 @@ public interface RedisScriptingCommands { * @param returnType must not be {@literal null}. * @param numKeys * @param keysAndArgs must not be {@literal null}. - * @return + * @return script result. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: EVAL */ + @Nullable T eval(byte[] script, ReturnType returnType, int numKeys, byte[]... keysAndArgs); /** @@ -79,9 +85,10 @@ public interface RedisScriptingCommands { * @param returnType must not be {@literal null}. * @param numKeys * @param keysAndArgs must not be {@literal null}. - * @return + * @return script result. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: EVALSHA */ + @Nullable T evalSha(String scriptSha, ReturnType returnType, int numKeys, byte[]... keysAndArgs); /** @@ -91,9 +98,10 @@ public interface RedisScriptingCommands { * @param returnType must not be {@literal null}. * @param numKeys * @param keysAndArgs must not be {@literal null}. - * @return + * @return script result. {@literal null} when used in pipeline / transaction. * @since 1.5 * @see Redis Documentation: EVALSHA */ + @Nullable T evalSha(byte[] scriptSha, ReturnType returnType, int numKeys, byte[]... keysAndArgs); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisSentinelCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisSentinelCommands.java index 7e8009002..ab6a6d00d 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisSentinelCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisSentinelCommands.java @@ -36,7 +36,7 @@ public interface RedisSentinelCommands { /** * Get a {@link Collection} of monitored masters and their state. - * + * * @return Collection of {@link RedisServer}s. Never {@literal null}. */ Collection masters(); diff --git a/src/main/java/org/springframework/data/redis/connection/RedisSentinelConfiguration.java b/src/main/java/org/springframework/data/redis/connection/RedisSentinelConfiguration.java index c792174a3..1def208f6 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisSentinelConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisSentinelConfiguration.java @@ -27,6 +27,7 @@ import java.util.Set; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -45,7 +46,7 @@ public class RedisSentinelConfiguration { private static final String REDIS_SENTINEL_MASTER_CONFIG_PROPERTY = "spring.redis.sentinel.master"; private static final String REDIS_SENTINEL_NODES_CONFIG_PROPERTY = "spring.redis.sentinel.nodes"; - private NamedNode master; + private @Nullable NamedNode master; private Set sentinels; private int database; private RedisPassword password = RedisPassword.none(); @@ -162,8 +163,9 @@ public class RedisSentinelConfiguration { /** * Get the {@literal Sentinel} master node. * - * @return get the master node. + * @return get the master node or {@literal null} if not set. */ + @Nullable public NamedNode getMaster() { return master; } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java index d5a3d9af7..3ffe77120 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisServerCommands.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Properties; import org.springframework.data.redis.core.types.RedisClientInfo; +import org.springframework.lang.Nullable; /** * Server-specific commands supported by Redis. @@ -30,14 +31,14 @@ import org.springframework.data.redis.core.types.RedisClientInfo; */ public interface RedisServerCommands { - public enum ShutdownOption { + enum ShutdownOption { SAVE, NOSAVE; } /** * @since 1.7 */ - public enum MigrateOption { + enum MigrateOption { COPY, REPLACE } @@ -70,9 +71,10 @@ public interface RedisServerCommands { /** * Get time of last {@link #bgSave()} operation in seconds. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LASTSAVE */ + @Nullable Long lastSave(); /** @@ -85,9 +87,10 @@ public interface RedisServerCommands { /** * Get the total number of available keys in currently selected database. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: DBSIZE */ + @Nullable Long dbSize(); /** @@ -113,17 +116,19 @@ public interface RedisServerCommands { * *

* - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: INFO */ + @Nullable Properties info(); /** * Load server information for given {@code selection}. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: INFO */ + @Nullable Properties info(String section); /** @@ -145,16 +150,17 @@ public interface RedisServerCommands { * Load configuration parameters for given {@code pattern} from server. * * @param pattern must not be {@literal null}. - * @return never {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: CONFIG GET */ + @Nullable Properties getConfig(String pattern); /** * Set server configuration for {@code param} to {@code value}. * - * @param param - * @param value + * @param param must not be {@literal null}. + * @param value must not be {@literal null}. * @see Redis Documentation: CONFIG SET */ void setConfig(String param, String value); @@ -170,10 +176,11 @@ public interface RedisServerCommands { /** * Request server timestamp using {@code TIME} command. * - * @return current server time in milliseconds. + * @return current server time in milliseconds or {@literal null} when used in pipeline / transaction. * @since 1.1 * @see Redis Documentation: TIME */ + @Nullable Long time(); /** @@ -199,18 +206,20 @@ public interface RedisServerCommands { * Returns the name of the current connection. * * @see Redis Documentation: CLIENT GETNAME - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.3 */ + @Nullable String getClientName(); /** * Request information and statistics about connected clients. * - * @return {@link List} of {@link RedisClientInfo} objects. + * @return {@link List} of {@link RedisClientInfo} objects or {@literal null} when used in pipeline / transaction. * @since 1.3 * @see Redis Documentation: CLIENT LIST */ + @Nullable List getClientList(); /** @@ -242,7 +251,7 @@ public interface RedisServerCommands { * @since 1.7 * @see Redis Documentation: MIGRATE */ - void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option); + void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option); /** * Atomically transfer a key from a source Redis instance to a destination Redis instance. On success the key is @@ -256,5 +265,5 @@ public interface RedisServerCommands { * @since 1.7 * @see Redis Documentation: MIGRATE */ - void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option, long timeout); + void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, long timeout); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisSetCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisSetCommands.java index 461946d1f..28ffdfc6d 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisSetCommands.java @@ -20,6 +20,7 @@ import java.util.Set; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.lang.Nullable; /** * Set-specific commands supported by Redis. @@ -34,29 +35,32 @@ public interface RedisSetCommands { * Add given {@code values} to set at {@code key}. * * @param key must not be {@literal null}. - * @param values - * @return + * @param values must not be empty. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SADD */ + @Nullable Long sAdd(byte[] key, byte[]... values); /** * Remove given {@code values} from set at {@code key} and return the number of removed elements. * * @param key must not be {@literal null}. - * @param values - * @return + * @param values must not be empty. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SREM */ + @Nullable Long sRem(byte[] key, byte[]... values); /** * Remove and return a random member from set at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when key does not exist or used in pipeline / transaction. * @see Redis Documentation: SPOP */ + @Nullable byte[] sPop(byte[] key); /** @@ -64,10 +68,11 @@ public interface RedisSetCommands { * * @param key must not be {@literal null}. * @param count number of random members to pop from the set. - * @return empty {@link List} if set does not exist. Never {@literal null}. + * @return empty {@link List} if set does not exist. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SPOP * @since 2.0 */ + @Nullable List sPop(byte[] key, long count); /** @@ -75,38 +80,42 @@ public interface RedisSetCommands { * * @param srcKey must not be {@literal null}. * @param destKey must not be {@literal null}. - * @param value - * @return + * @param value must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SMOVE */ + @Nullable Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value); /** * 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 sCard(byte[] key); /** * Check if set at {@code key} contains {@code value}. * * @param key must not be {@literal null}. - * @param value - * @return + * @param value must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SISMEMBER */ + @Nullable Boolean sIsMember(byte[] key, byte[] value); /** * Returns the members intersecting all given sets at {@code keys}. * * @param keys must not be {@literal null}. - * @return + * @return empty {@link Set} if no intersection found. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SINTER */ + @Nullable Set sInter(byte[]... keys); /** @@ -114,18 +123,20 @@ public interface RedisSetCommands { * * @param destKey must not be {@literal null}. * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SINTERSTORE */ + @Nullable Long sInterStore(byte[] destKey, byte[]... keys); /** * Union all sets at given {@code keys}. * * @param keys must not be {@literal null}. - * @return + * @return empty {@link Set} if keys do not exist. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SUNION */ + @Nullable Set sUnion(byte[]... keys); /** @@ -133,18 +144,20 @@ public interface RedisSetCommands { * * @param destKey must not be {@literal null}. * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SUNIONSTORE */ + @Nullable Long sUnionStore(byte[] destKey, byte[]... keys); /** * Diff all sets for given {@code keys}. * * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SDIFF */ + @Nullable Set sDiff(byte[]... keys); /** @@ -152,27 +165,30 @@ public interface RedisSetCommands { * * @param destKey must not be {@literal null}. * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SDIFFSTORE */ + @Nullable Long sDiffStore(byte[] destKey, byte[]... keys); /** * Get all elements of set at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return empty {@link Set} when key does not exist. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SMEMBERS */ + @Nullable Set sMembers(byte[] key); /** * Get random element from set at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return can be {@literal null}. * @see Redis Documentation: SRANDMEMBER */ + @Nullable byte[] sRandMember(byte[] key); /** @@ -180,9 +196,10 @@ public interface RedisSetCommands { * * @param key must not be {@literal null}. * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SRANDMEMBER */ + @Nullable List sRandMember(byte[] key, long count); /** @@ -190,7 +207,7 @@ public interface RedisSetCommands { * * @param key must not be {@literal null}. * @param options must not be {@literal null}. - * @return + * @return never {@literal null}. * @since 1.4 * @see Redis Documentation: SCAN */ 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 489c46f3e..6963739ca 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisStringCommands.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; import org.springframework.data.redis.core.types.Expiration; +import org.springframework.lang.Nullable; /** * String/Value-specific commands supported by Redis. @@ -37,28 +38,31 @@ public interface RedisStringCommands { * Get the value of {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when key does not exist or used in pipeline / transaction. * @see Redis Documentation: GET */ + @Nullable byte[] get(byte[] key); /** * Set {@code value} of {@code key} and return its old value. * * @param key must not be {@literal null}. - * @param value - * @return + * @param value must not be {@literal null}. + * @return {@literal null} if key did not exist before or when used in pipeline / transaction. * @see Redis Documentation: GETSET */ + @Nullable byte[] getSet(byte[] key, byte[] value); /** * Get multiple {@code keys}. Values are returned in the order of the requested keys. * - * @param keys must not be {@literal null}. - * @return + * @param keys must not be {@literal null}. + * @return empty {@link List} if keys do not exist or when used in pipeline / transaction. * @see Redis Documentation: MGET */ + @Nullable List mGet(byte[]... keys); /** @@ -76,8 +80,8 @@ public interface RedisStringCommands { * * @param key must not be {@literal null}. * @param value must not be {@literal null}. - * @param expiration can be {@literal null}. Defaulted to {@link Expiration#persistent()}. - * @param option can be {@literal null}. Defaulted to {@link SetOption#UPSERT}. + * @param expiration must not be {@literal null}. Use {@link Expiration#persistent()} to not set any ttl. + * @param option must not be {@literal null}. Use {@link SetOption#upsert()} to add non existing. * @since 1.7 * @see Redis Documentation: SET */ @@ -117,7 +121,7 @@ public interface RedisStringCommands { /** * Set multiple keys to multiple values using key-value pairs provided in {@code tuple}. * - * @param tuple must not be {@literal null}. + * @param tuple must not be {@literal null}. * @see Redis Documentation: MSET */ void mSet(Map tuple); @@ -164,7 +168,7 @@ public interface RedisStringCommands { * Decrement an integer value stored as string value of {@code key} by 1. * * @param key must not be {@literal null}. - * @return + * @return never {@literal null}. * @see Redis Documentation: DECR */ Long decr(byte[] key); @@ -174,7 +178,7 @@ public interface RedisStringCommands { * * @param key must not be {@literal null}. * @param value - * @return + * @return never {@literal null}. * @see Redis Documentation: DECRBY */ Long decrBy(byte[] key, long value); @@ -183,8 +187,8 @@ public interface RedisStringCommands { * Append a {@code value} to {@code key}. * * @param key must not be {@literal null}. - * @param value - * @return + * @param value must not be {@literal null}. + * @return never {@literal null}. * @see Redis Documentation: APPEND */ Long append(byte[] key, byte[] value); @@ -215,7 +219,7 @@ public interface RedisStringCommands { * * @param key must not be {@literal null}. * @param offset - * @return + * @return never {@literal null}. * @see Redis Documentation: GETBIT */ Boolean getBit(byte[] key, long offset); @@ -235,7 +239,7 @@ public interface RedisStringCommands { * Count the number of set bits (population counting) in value stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return never {@literal null}. * @see Redis Documentation: BITCOUNT */ Long bitCount(byte[] key); @@ -247,7 +251,7 @@ public interface RedisStringCommands { * @param key must not be {@literal null}. * @param begin * @param end - * @return + * @return never {@literal null}. * @see Redis Documentation: BITCOUNT */ Long bitCount(byte[] key, long begin, long end); @@ -255,10 +259,10 @@ public interface RedisStringCommands { /** * Perform bitwise operations between strings. * - * @param op must not be {@literal null}. + * @param op must not be {@literal null}. * @param destination must not be {@literal null}. * @param keys must not be {@literal null}. - * @return + * @return never {@literal null}. * @see Redis Documentation: BITOP */ Long bitOp(BitOperation op, byte[] destination, byte[]... keys); diff --git a/src/main/java/org/springframework/data/redis/connection/RedisSubscribedConnectionException.java b/src/main/java/org/springframework/data/redis/connection/RedisSubscribedConnectionException.java index b87d9cea9..0bb927f01 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisSubscribedConnectionException.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisSubscribedConnectionException.java @@ -1,5 +1,5 @@ /* - * 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. @@ -16,11 +16,13 @@ package org.springframework.data.redis.connection; import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.lang.Nullable; /** * Exception thrown when issuing commands on a connection that is subscribed and waiting for events. * * @author Costin Leau + * @author Christoph Strobl * @see org.springframework.data.redis.connection.RedisPubSubCommands */ public class RedisSubscribedConnectionException extends InvalidDataAccessApiUsageException { @@ -31,7 +33,7 @@ public class RedisSubscribedConnectionException extends InvalidDataAccessApiUsag * @param msg * @param cause */ - public RedisSubscribedConnectionException(String msg, Throwable cause) { + public RedisSubscribedConnectionException(@Nullable String msg, @Nullable Throwable cause) { super(msg, cause); } diff --git a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java index d67b238f1..99a761882 100644 --- a/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/RedisZSetCommands.java @@ -19,6 +19,7 @@ import java.util.Set; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -44,8 +45,14 @@ public interface RedisZSetCommands { */ interface Tuple extends Comparable { + /** + * @return the raw value of the member. + */ byte[] getValue(); + /** + * @return the member score value used for sorting. + */ Double getScore(); } @@ -57,8 +64,8 @@ public interface RedisZSetCommands { */ class Range { - Boundary min; - Boundary max; + @Nullable Boundary min; + @Nullable Boundary max; /** * @return new {@link Range} @@ -81,8 +88,8 @@ public interface RedisZSetCommands { /** * Greater Than Equals * - * @param min - * @return + * @param min must not be {@literal null}. + * @return this. */ public Range gte(Object min) { @@ -94,8 +101,8 @@ public interface RedisZSetCommands { /** * Greater Than * - * @param min - * @return + * @param min must not be {@literal null}. + * @return this. */ public Range gt(Object min) { @@ -107,8 +114,8 @@ public interface RedisZSetCommands { /** * Less Then Equals * - * @param max - * @return + * @param max must not be {@literal null}. + * @return this. */ public Range lte(Object max) { @@ -120,8 +127,8 @@ public interface RedisZSetCommands { /** * Less Than * - * @param max - * @return + * @param max must not be {@literal null}. + * @return this. */ public Range lt(Object max) { @@ -133,6 +140,7 @@ public interface RedisZSetCommands { /** * @return {@literal null} if not set. */ + @Nullable public Boundary getMin() { return min; } @@ -140,6 +148,7 @@ public interface RedisZSetCommands { /** * @return {@literal null} if not set. */ + @Nullable public Boundary getMax() { return max; } @@ -150,18 +159,19 @@ public interface RedisZSetCommands { */ public static class Boundary { - Object value; + @Nullable Object value; boolean including; static Boundary infinite() { return new Boundary(null, true); } - Boundary(Object value, boolean including) { + Boundary(@Nullable Object value, boolean including) { this.value = value; this.including = including; } + @Nullable public Object getValue() { return value; } @@ -179,6 +189,19 @@ public interface RedisZSetCommands { */ class Limit { + private static final Limit UNLIMITED = new Limit() { + + @Override + public int getCount() { + return -1; + } + + @Override + public int getOffset() { + return super.getOffset(); + } + }; + int offset; int count; @@ -203,6 +226,18 @@ public interface RedisZSetCommands { public int getOffset() { return offset; } + + public boolean isUnlimited() { + return this.equals(UNLIMITED); + } + + /** + * @return new {@link Limit} indicating no limit; + * @since 1.3 + */ + public static Limit unlimited() { + return UNLIMITED; + } } /** @@ -211,9 +246,10 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param score the score. * @param value the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZADD */ + @Nullable Boolean zAdd(byte[] key, double score, byte[] value); /** @@ -221,9 +257,10 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param tuples must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZADD */ + @Nullable Long zAdd(byte[] key, Set tuples); /** @@ -231,9 +268,10 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param values must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREM */ + @Nullable Long zRem(byte[] key, byte[]... values); /** @@ -242,19 +280,21 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param increment * @param value the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZINCRBY */ + @Nullable Double zIncrBy(byte[] key, double increment, byte[] value); /** * Determine the index of element with {@code value} in a sorted set. * * @param key must not be {@literal null}. - * @param value the value. - * @return + * @param value the value. Must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANK */ + @Nullable Long zRank(byte[] key, byte[] value); /** @@ -262,9 +302,10 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param value the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANK */ + @Nullable Long zRevRank(byte[] key, byte[] value); /** @@ -273,9 +314,11 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZRANGE */ + @Nullable Set zRange(byte[] key, long start, long end); /** @@ -284,9 +327,11 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZRANGE */ + @Nullable Set zRangeWithScores(byte[] key, long start, long end); /** @@ -295,9 +340,11 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable default Set zRangeByScore(byte[] key, double min, double max) { return zRangeByScore(key, new Range().gte(min).lte(max)); } @@ -307,12 +354,14 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @since 1.6 * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable default Set zRangeByScoreWithScores(byte[] key, Range range) { - return zRangeByScoreWithScores(key, range, null); + return zRangeByScoreWithScores(key, range, Limit.unlimited()); } /** @@ -321,9 +370,11 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable default Set zRangeByScoreWithScores(byte[] key, double min, double max) { return zRangeByScoreWithScores(key, new Range().gte(min).lte(max)); } @@ -337,9 +388,11 @@ public interface RedisZSetCommands { * @param max * @param offset * @param count - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable default Set zRangeByScore(byte[] key, double min, double max, long offset, long count) { return zRangeByScore(key, new Range().gte(min).lte(max), new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); @@ -349,14 +402,16 @@ public interface RedisZSetCommands { * Get set of {@link Tuple}s in range from {@code start} to {@code end} where score is between {@code min} and * {@code max} from sorted set. * - * @param key + * @param key must not be {@literal null}. * @param min * @param max * @param offset * @param count - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable default Set zRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { return zRangeByScoreWithScores(key, new Range().gte(min).lte(max), new Limit().offset(Long.valueOf(offset).intValue()).count(Long.valueOf(count).intValue())); @@ -368,11 +423,13 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param limit - * @return + * @param limit must not be {@literal null}. + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @since 1.6 * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit); /** @@ -381,9 +438,11 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZREVRANGE */ + @Nullable Set zRevRange(byte[] key, long start, long end); /** @@ -392,9 +451,11 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZREVRANGE */ + @Nullable Set zRevRangeWithScores(byte[] key, long start, long end); /** @@ -403,9 +464,11 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZREVRANGE */ + @Nullable default Set zRevRangeByScore(byte[] key, double min, double max) { return zRevRangeByScore(key, new Range().gte(min).lte(max)); } @@ -416,12 +479,14 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @since 1.6 * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable default Set zRevRangeByScore(byte[] key, Range range) { - return zRevRangeByScore(key, range, null); + return zRevRangeByScore(key, range, Limit.unlimited()); } /** @@ -431,11 +496,13 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return empty {@link Set} when key does not exists or no members in range. {@literal null} when used in pipeline / + * transaction. * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable default Set zRevRangeByScoreWithScores(byte[] key, double min, double max) { - return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), null); + return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), Limit.unlimited()); } /** @@ -447,9 +514,10 @@ public interface RedisZSetCommands { * @param max * @param offset * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable default Set zRevRangeByScore(byte[] key, double min, double max, long offset, long count) { return zRevRangeByScore(key, new Range().gte(min).lte(max), @@ -462,11 +530,12 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param limit - * @return + * @param limit must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable Set zRevRangeByScore(byte[] key, Range range, Limit limit); /** @@ -478,9 +547,10 @@ public interface RedisZSetCommands { * @param max * @param offset * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable default Set zRevRangeByScoreWithScores(byte[] key, double min, double max, long offset, long count) { return zRevRangeByScoreWithScores(key, new Range().gte(min).lte(max), @@ -493,12 +563,13 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable default Set zRevRangeByScoreWithScores(byte[] key, Range range) { - return zRevRangeByScoreWithScores(key, range, null); + return zRevRangeByScoreWithScores(key, range, Limit.unlimited()); } /** @@ -507,11 +578,12 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param limit - * @return + * @param limit must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit); /** @@ -520,9 +592,10 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZCOUNT */ + @Nullable default Long zCount(byte[] key, double min, double max) { return zCount(key, new Range().gte(min).lte(max)); } @@ -532,19 +605,21 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZCOUNT */ + @Nullable Long zCount(byte[] key, Range range); /** * Get the size of sorted set with {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZCARD */ + @Nullable Long zCard(byte[] key); /** @@ -552,9 +627,10 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param value the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZSCORE */ + @Nullable Double zScore(byte[] key, byte[] value); /** @@ -563,9 +639,10 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREMRANGEBYRANK */ + @Nullable Long zRemRange(byte[] key, long start, long end); /** @@ -574,9 +651,10 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREMRANGEBYSCORE */ + @Nullable default Long zRemRangeByScore(byte[] key, double min, double max) { return zRemRangeByScore(key, new Range().gte(min).lte(max)); } @@ -586,10 +664,11 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZREMRANGEBYSCORE */ + @Nullable Long zRemRangeByScore(byte[] key, Range range); /** @@ -597,9 +676,10 @@ public interface RedisZSetCommands { * * @param destKey must not be {@literal null}. * @param sets must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZUNIONSTORE */ + @Nullable Long zUnionStore(byte[] destKey, byte[]... sets); /** @@ -609,9 +689,10 @@ public interface RedisZSetCommands { * @param aggregate must not be {@literal null}. * @param weights * @param sets must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZUNIONSTORE */ + @Nullable Long zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets); /** @@ -619,9 +700,10 @@ public interface RedisZSetCommands { * * @param destKey must not be {@literal null}. * @param sets must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZINTERSTORE */ + @Nullable Long zInterStore(byte[] destKey, byte[]... sets); /** @@ -634,6 +716,7 @@ public interface RedisZSetCommands { * @return * @see Redis Documentation: ZINTERSTORE */ + @Nullable Long zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets); /** @@ -653,10 +736,11 @@ public interface RedisZSetCommands { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.5 * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable default Set zRangeByScore(byte[] key, String min, String max) { return zRangeByScore(key, new Range().gte(min).lte(max)); } @@ -666,12 +750,13 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable default Set zRangeByScore(byte[] key, Range range) { - return zRangeByScore(key, range, null); + return zRangeByScore(key, range, Limit.unlimited()); } /** @@ -683,10 +768,11 @@ public interface RedisZSetCommands { * @param max must not be {@literal null}. * @param offset * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.5 * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable Set zRangeByScore(byte[] key, String min, String max, long offset, long count); /** @@ -695,21 +781,23 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param limit - * @return + * @param limit must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable Set zRangeByScore(byte[] key, Range range, Limit limit); /** * Get all the elements in the sorted set at {@literal key} in lexicographical ordering. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZRANGEBYLEX */ + @Nullable default Set zRangeByLex(byte[] key) { return zRangeByLex(key, Range.unbounded()); } @@ -719,12 +807,13 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZRANGEBYLEX */ + @Nullable default Set zRangeByLex(byte[] key, Range range) { - return zRangeByLex(key, range, null); + return zRangeByLex(key, range, Limit.unlimited()); } /** @@ -733,11 +822,12 @@ public interface RedisZSetCommands { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. - * @param range can be {@literal null}. - * @return + * @param limit must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @since 1.6 * @see Redis Documentation: ZRANGEBYLEX */ + @Nullable Set zRangeByLex(byte[] key, Range range, Limit limit); } diff --git a/src/main/java/org/springframework/data/redis/connection/ReturnType.java b/src/main/java/org/springframework/data/redis/connection/ReturnType.java index cf7162624..b125eb551 100644 --- a/src/main/java/org/springframework/data/redis/connection/ReturnType.java +++ b/src/main/java/org/springframework/data/redis/connection/ReturnType.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. @@ -17,11 +17,14 @@ package org.springframework.data.redis.connection; import java.util.List; +import org.springframework.lang.Nullable; + /** * Represents a data type returned from Redis, currently used to denote the expected return type of Redis scripting * commands * * @author Jennifer Hickey + * @author Christoph Strobl */ public enum ReturnType { @@ -50,7 +53,12 @@ public enum ReturnType { */ VALUE; - public static ReturnType fromJavaType(Class javaType) { + /** + * @param javaType can be {@literal null} which translates to {@link ReturnType#STATUS}. + * @return never {@literal null}. + */ + public static ReturnType fromJavaType(@Nullable Class javaType) { + if (javaType == null) { return ReturnType.STATUS; } diff --git a/src/main/java/org/springframework/data/redis/connection/SortParameters.java b/src/main/java/org/springframework/data/redis/connection/SortParameters.java index 150205d84..81b64a737 100644 --- a/src/main/java/org/springframework/data/redis/connection/SortParameters.java +++ b/src/main/java/org/springframework/data/redis/connection/SortParameters.java @@ -1,5 +1,5 @@ /* - * 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. @@ -15,24 +15,28 @@ */ package org.springframework.data.redis.connection; +import org.springframework.lang.Nullable; + /** * Entity containing the parameters for the SORT operation. - * + * * @author Costin Leau + * @author Christoph Strobl */ public interface SortParameters { /** * Sorting order. */ - public enum Order { + enum Order { ASC, DESC } /** * Utility class wrapping the 'LIMIT' setting. */ - static class Range { + class Range { + private final long start; private final long count; @@ -52,37 +56,42 @@ public interface SortParameters { /** * Returns the sorting order. Can be null if nothing is specified. - * - * @return sorting order + * + * @return sorting order. {@literal null} if not set. */ + @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 + * + * @return the type of sorting. {@literal null} if not set. */ + @Nullable Boolean isAlphabetic(); /** * Returns the pattern (if set) for sorting by external keys (BY). Can be null if nothing is specified. - * - * @return BY pattern. + * + * @return BY pattern. {@literal null} if not set. */ + @Nullable byte[] getByPattern(); /** * Returns the pattern (if set) for retrieving external keys (GET). Can be null if nothing is specified. - * - * @return GET pattern. + * + * @return GET pattern. {@literal null} if not set. */ + @Nullable byte[][] getGetPattern(); /** * Returns the sorting limit (range or pagination). Can be null if nothing is specified. - * - * @return sorting limit/range + * + * @return sorting limit/range. {@literal null} if not set. */ + @Nullable Range getLimit(); } diff --git a/src/main/java/org/springframework/data/redis/connection/Subscription.java b/src/main/java/org/springframework/data/redis/connection/Subscription.java index 91e380be1..1b5b9c566 100644 --- a/src/main/java/org/springframework/data/redis/connection/Subscription.java +++ b/src/main/java/org/springframework/data/redis/connection/Subscription.java @@ -1,5 +1,5 @@ /* - * 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. @@ -22,20 +22,21 @@ import java.util.Collection; * threads. Note that once a subscription died, it cannot accept any more subscriptions. * * @author Costin Leau + * @author Christoph Strobl */ public interface Subscription { /** * Adds the given channels to the current subscription. - * - * @param channels channel names + * + * @param channels channel names. Must not be empty. */ void subscribe(byte[]... channels) throws RedisInvalidSubscriptionException; /** * Adds the given channel patterns to the current subscription. - * - * @param patterns channel patterns + * + * @param patterns channel patterns. Must not be empty. */ void pSubscribe(byte[]... patterns) throws RedisInvalidSubscriptionException; @@ -46,8 +47,8 @@ public interface Subscription { /** * Cancels the current subscription for all given channels. - * - * @param channels channel names + * + * @param channels channel names. Must not be empty. */ void unsubscribe(byte[]... channels); @@ -58,35 +59,35 @@ public interface Subscription { /** * Cancels the subscription for all channels matching the given patterns. - * - * @param patterns + * + * @param patterns must not be empty. */ void pUnsubscribe(byte[]... patterns); /** * Returns the (named) channels for this subscription. - * + * * @return collection of named channels */ Collection getChannels(); /** * Returns the channel patters for this subscription. - * + * * @return collection of channel patterns */ Collection getPatterns(); /** * Returns the listener used for this subscription. - * + * * @return the listener used for this subscription. */ MessageListener getListener(); /** * Indicates whether this subscription is still 'alive' or not. - * + * * @return true if the subscription still applies, false otherwise. */ boolean isAlive(); 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 5845603a7..1bb816c17 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 @@ -46,6 +46,7 @@ import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisNode.NodeType; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.NumberUtils; @@ -95,11 +96,13 @@ abstract public class Converters { String[] args = source.split(" "); String[] hostAndPort = StringUtils.split(args[HOST_PORT_INDEX], ":"); + Assert.notNull(hostAndPort, "CusterNode information does not define host and port!"); + SlotRange range = parseSlotRange(args); Set flags = parseFlags(args); String portPart = hostAndPort[1]; - if (portPart.contains("@")) { + if (portPart != null && portPart.contains("@")) { portPart = portPart.substring(0, portPart.indexOf('@')); } @@ -211,7 +214,9 @@ abstract public class Converters { } public static Properties toProperties(Map source) { - return MAP_TO_PROPERTIES.convert(source); + + Properties properties = MAP_TO_PROPERTIES.convert(source); + return properties != null ? properties : new Properties(); } public static Boolean toBoolean(Long source) { @@ -424,7 +429,11 @@ abstract public class Converters { INSTANCE; - DistanceConverter forMetric(Metric metric) { + /** + * @param metric can be {@literal null}. Defaults to {@link DistanceUnit#METERS}. + * @return never {@literal null}. + */ + DistanceConverter forMetric(@Nullable Metric metric) { return new DistanceConverter( metric == null || ObjectUtils.nullSafeEquals(Metrics.NEUTRAL, metric) ? DistanceUnit.METERS : metric); } @@ -433,14 +442,22 @@ abstract public class Converters { private Metric metric; - public DistanceConverter(Metric metric) { + /** + * @param metric can be {@literal null}. Defaults to {@link DistanceUnit#METERS}. + * @return never {@literal null}. + */ + DistanceConverter(@Nullable Metric metric) { this.metric = metric == null || ObjectUtils.nullSafeEquals(Metrics.NEUTRAL, metric) ? DistanceUnit.METERS : metric; } + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ @Override public Distance convert(Double source) { - return source == null ? null : new Distance(source, metric); + return new Distance(source, metric); } } } @@ -456,13 +473,13 @@ abstract public class Converters { final RedisSerializer serializer; + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ @Override public GeoResults> convert(GeoResults> source) { - if (source == null) { - return new GeoResults<>(Collections.>> emptyList()); - } - List>> values = new ArrayList<>(source.getContent().size()); for (GeoResult> value : source.getContent()) { 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 569075250..7f5b2f176 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 @@ -1,5 +1,5 @@ /* - * Copyright 2017 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. @@ -25,6 +25,7 @@ import org.springframework.core.convert.converter.Converter; * * @author Jennifer Hickey * @author Mark Paluch + * @author Christoph Strobl * @param The type of elements in the List to convert * @param The type of elements in the converted List */ @@ -39,12 +40,13 @@ public class ListConverter implements Converter, List> { this.itemConverter = itemConverter; } + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ + @Override public List convert(List source) { - if (source == null) { - return null; - } - List results = new ArrayList<>(); for (S result : source) { results.add(itemConverter.convert(result)); diff --git a/src/main/java/org/springframework/data/redis/connection/convert/LongToBooleanConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/LongToBooleanConverter.java index 42414af66..80f80196c 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/LongToBooleanConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/LongToBooleanConverter.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. @@ -21,11 +21,17 @@ import org.springframework.core.convert.converter.Converter; * Converts Longs to Booleans * * @author Jennifer Hickey + * @author Christoph Strobl */ public class LongToBooleanConverter implements Converter { + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ + @Override public Boolean convert(Long result) { - return result != null ? result == 1 : null; + return result == 1; } } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/MapConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/MapConverter.java index 5f1163e3a..d54b98a3e 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/MapConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/MapConverter.java @@ -15,16 +15,18 @@ */ package org.springframework.data.redis.connection.convert; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.collections.map.HashedMap; import org.springframework.core.convert.converter.Converter; /** * Converts a Map of values of one key/value type to a Map of values of another type * * @author Jennifer Hickey + * @author Christoph Strobl * @param The type of keys and values in the Map to convert * @param The type of keys and values in the converted Map */ @@ -33,31 +35,24 @@ public class MapConverter implements Converter, Map> { private Converter itemConverter; /** - * @param itemConverter The {@link Converter} to use for converting individual Map keys and values + * @param itemConverter The {@link Converter} to use for converting individual Map keys and values. Must not be + * {@literal null}. */ public MapConverter(Converter itemConverter) { this.itemConverter = itemConverter; } + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ + @Override public Map convert(Map source) { - if (source == null) { - return null; - } + return source.entrySet().stream() + .collect(Collectors.toMap(e -> itemConverter.convert(e.getKey()), e -> itemConverter.convert(e.getValue()), + (a, b) -> a, source instanceof LinkedHashMap ? LinkedHashMap::new : HashedMap::new)); - Map results; - - if (source instanceof LinkedHashMap) { - results = new LinkedHashMap<>(); - } else { - results = new HashMap<>(); - } - - for (Map.Entry result : source.entrySet()) { - results.put(itemConverter.convert(result.getKey()), itemConverter.convert(result.getValue())); - } - - return results; } } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/MapToPropertiesConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/MapToPropertiesConverter.java index 4c04af967..431062181 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/MapToPropertiesConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/MapToPropertiesConverter.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. @@ -25,16 +25,19 @@ import org.springframework.core.convert.converter.Converter; * @since 1.4 */ public enum MapToPropertiesConverter implements Converter, Properties> { + INSTANCE; + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ @Override public Properties convert(Map source) { - Properties p = new Properties(); - if (source != null) { - p.putAll(source); - } - return p; + Properties target = new Properties(); + target.putAll(source); + return target; } } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java index f6c507e93..c05c67223 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/SetConverter.java @@ -18,13 +18,16 @@ package org.springframework.data.redis.connection.convert; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; +import java.util.stream.Collectors; import org.springframework.core.convert.converter.Converter; +import org.springframework.util.Assert; /** * Converts a Set of values of one type to a Set of values of another type * * @author Jennifer Hickey + * @author Christoph Strobl * @param The type of elements in the Set to convert * @param The type of elements in the converted Set */ @@ -33,31 +36,23 @@ public class SetConverter implements Converter, Set> { private Converter itemConverter; /** - * @param itemConverter The {@link Converter} to use for converting individual Set items + * @param itemConverter The {@link Converter} to use for converting individual Set items. Must not be {@literal null}. */ public SetConverter(Converter itemConverter) { + + Assert.notNull(itemConverter, "ItemConverter must not be null!"); this.itemConverter = itemConverter; } + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ + @Override public Set convert(Set source) { - if (source == null) { - return null; - } - - Set results; - - if (source instanceof LinkedHashSet) { - results = new LinkedHashSet<>(); - } else { - results = new HashSet<>(); - } - - for (S result : source) { - results.add(itemConverter.convert(result)); - } - - return results; + return source.stream().map(itemConverter::convert) + .collect(Collectors.toCollection(source instanceof LinkedHashSet ? LinkedHashSet::new : HashSet::new)); } } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/StringToDataTypeConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/StringToDataTypeConverter.java index 933143d5c..5d62ffa59 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/StringToDataTypeConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/StringToDataTypeConverter.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. @@ -20,15 +20,18 @@ import org.springframework.data.redis.connection.DataType; /** * Converts Strings to {@link DataType}s - * + * * @author Jennifer Hickey + * @author Christoph Strobl */ public class StringToDataTypeConverter implements Converter { + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ + @Override public DataType convert(String source) { - if (source == null) { - return null; - } return DataType.fromCode(source); } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/StringToPropertiesConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/StringToPropertiesConverter.java index ca8d99305..97d62e676 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/StringToPropertiesConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/StringToPropertiesConverter.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. @@ -23,23 +23,24 @@ import org.springframework.data.redis.RedisSystemException; /** * Converts Strings to {@link Properties} - * + * * @author Jennifer Hickey + * @author Christoph Strobl */ public class StringToPropertiesConverter implements Converter { + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ + @Override public Properties convert(String source) { - if (source == null) { - return null; - } + Properties info = new Properties(); - StringReader stringReader = new StringReader(source); - try { + try (StringReader stringReader = new StringReader(source)) { info.load(stringReader); } catch (Exception ex) { throw new RedisSystemException("Cannot read Redis info", ex); - } finally { - stringReader.close(); } return info; } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java index 684b8df70..696a31036 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/StringToRedisClientInfoConverter.java @@ -16,7 +16,6 @@ package org.springframework.data.redis.connection.convert; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.springframework.core.convert.converter.Converter; @@ -36,19 +35,19 @@ import org.springframework.data.redis.core.types.RedisClientInfo.RedisClientInfo */ public class StringToRedisClientInfoConverter implements Converter> { + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ @Override public List convert(String[] lines) { - if (lines == null) { - return Collections.emptyList(); - } - - List infos = new ArrayList<>(lines.length); + List clientInfoList = new ArrayList<>(lines.length); for (String line : lines) { - infos.add(RedisClientInfoBuilder.fromString(line)); + clientInfoList.add(RedisClientInfoBuilder.fromString(line)); } - return infos; + return clientInfoList; } } diff --git a/src/main/java/org/springframework/data/redis/connection/convert/TransactionResultConverter.java b/src/main/java/org/springframework/data/redis/connection/convert/TransactionResultConverter.java index 0efb608ce..ac92e886c 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/TransactionResultConverter.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/TransactionResultConverter.java @@ -22,6 +22,7 @@ import java.util.Queue; import org.springframework.core.convert.converter.Converter; import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.connection.FutureResult; /** @@ -29,6 +30,7 @@ import org.springframework.data.redis.connection.FutureResult; * objects returned in the list as well, using the supplied Exception {@link Converter} * * @author Jennifer Hickey + * @author Christoph Strobl * @param The type of {@link FutureResult} of the individual tx operations */ public class TransactionResultConverter implements Converter, List> { @@ -39,19 +41,22 @@ public class TransactionResultConverter implements Converter, Li public TransactionResultConverter(Queue> txResults, Converter exceptionConverter) { + this.txResults = txResults; this.exceptionConverter = exceptionConverter; } + /* + * (non-Javadoc) + * @see org.springframework.core.convert.converter.Converter#convert(Object) + */ + @Override public List convert(List execResults) { - if (execResults == null) { - return null; - } - if (execResults.size() != txResults.size()) { - throw new IllegalArgumentException("Incorrect number of transaction results. Expected: " + txResults.size() - + " Actual: " + execResults.size()); + + throw new IllegalArgumentException( + "Incorrect number of transaction results. Expected: " + txResults.size() + " Actual: " + execResults.size()); } List convertedResults = new ArrayList<>(); @@ -59,7 +64,11 @@ public class TransactionResultConverter implements Converter, Li for (Object result : execResults) { FutureResult futureResult = txResults.remove(); if (result instanceof Exception) { - throw exceptionConverter.convert((Exception) result); + + Exception source = (Exception) result; + DataAccessException convertedException = exceptionConverter.convert(source); + throw convertedException != null ? convertedException + : new RedisSystemException("Error reading future result.", source); } if (!(futureResult.isStatus())) { convertedResults.add(futureResult.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 new file mode 100644 index 000000000..51cc4f0bf --- /dev/null +++ b/src/main/java/org/springframework/data/redis/connection/convert/package-info.java @@ -0,0 +1,5 @@ +/** + * Redis specific converters used for sending data and parsing responses. + */ +@org.springframework.lang.NonNullApi +package org.springframework.data.redis.connection.convert; diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/DefaultJedisClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/jedis/DefaultJedisClientConfiguration.java index 0e9426763..408dd47d2 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/DefaultJedisClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/DefaultJedisClientConfiguration.java @@ -23,11 +23,13 @@ import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocketFactory; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.springframework.lang.Nullable; /** * Default implementation of {@literal JedisClientConfiguration}. * * @author Mark Paluch + * @author Christoph Strobl * @since 2.0 */ class DefaultJedisClientConfiguration implements JedisClientConfiguration { @@ -42,9 +44,10 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { private final Duration readTimeout; private final Duration connectTimeout; - DefaultJedisClientConfiguration(boolean useSsl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, - HostnameVerifier hostnameVerifier, boolean usePooling, GenericObjectPoolConfig poolConfig, String clientName, - Duration readTimeout, Duration connectTimeout) { + DefaultJedisClientConfiguration(boolean useSsl, @Nullable SSLSocketFactory sslSocketFactory, + @Nullable SSLParameters sslParameters, @Nullable HostnameVerifier hostnameVerifier, boolean usePooling, + @Nullable GenericObjectPoolConfig poolConfig, @Nullable String clientName, Duration readTimeout, + Duration connectTimeout) { this.useSsl = useSsl; this.sslSocketFactory = Optional.ofNullable(sslSocketFactory); @@ -57,7 +60,8 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { this.connectTimeout = connectTimeout; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration#useSsl() */ @Override @@ -65,7 +69,8 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { return useSsl; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration#getSslSocketFactory() */ @Override @@ -73,7 +78,8 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { return sslSocketFactory; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration#getSslParameters() */ @Override @@ -81,7 +87,8 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { return sslParameters; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration#getHostnameVerifier() */ @Override @@ -89,7 +96,8 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { return hostnameVerifier; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration#usePooling() */ @Override @@ -97,7 +105,8 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { return usePooling; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration#getPoolConfig() */ @Override @@ -105,7 +114,8 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { return poolConfig; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration#getClientName() */ @Override @@ -113,7 +123,8 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { return clientName; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration#getReadTimeout() */ @Override @@ -121,7 +132,8 @@ class DefaultJedisClientConfiguration implements JedisClientConfiguration { return readTimeout; } - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.data.redis.connection.jedis.JedisClientConfiguration#getConnectTimeout() */ @Override diff --git a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientConfiguration.java index b669e1dd8..9ab7071af 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisClientConfiguration.java @@ -27,6 +27,7 @@ import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocketFactory; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -263,12 +264,12 @@ public interface JedisClientConfiguration { JedisPoolingClientConfigurationBuilder, JedisSslClientConfigurationBuilder { private boolean useSsl; - private SSLSocketFactory sslSocketFactory; - private SSLParameters sslParameters; - private HostnameVerifier hostnameVerifier; + private @Nullable SSLSocketFactory sslSocketFactory; + private @Nullable SSLParameters sslParameters; + private @Nullable HostnameVerifier hostnameVerifier; private boolean usePooling; private GenericObjectPoolConfig poolConfig = new JedisPoolConfig(); - private String clientName; + private @Nullable String clientName; private Duration readTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT); private Duration connectTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT); 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 9620cacb0..06417c3ac 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,6 +15,8 @@ */ 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; @@ -74,7 +76,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { private ClusterCommandExecutor clusterCommandExecutor; private final boolean disposeClusterCommandExecutorOnClose; - private volatile JedisSubscription subscription; + private volatile @Nullable JedisSubscription subscription; /** * Create new {@link JedisClusterConnection} utilizing native connections via {@link JedisCluster}. @@ -810,7 +812,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { return connection; } - throw new IllegalStateException(String.format("Node %s is unknown to cluster", node)); + throw new DataAccessResourceFailureException(String.format("Node %s is unknown to cluster", node)); } private JedisPool getResourcePoolForSpecificNode(RedisClusterNode node) { @@ -855,7 +857,7 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection { private final Object lock = new Object(); private final JedisCluster cluster; private long time = 0; - private ClusterTopology cached; + private @Nullable ClusterTopology cached; /** * Create new {@link JedisClusterTopologyProvider}.s 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 ac7cdb23a..b17f2f988 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,6 +15,7 @@ */ package org.springframework.data.redis.connection.jedis; +import org.springframework.lang.Nullable; import redis.clients.jedis.BinaryJedis; import java.util.ArrayList; @@ -477,7 +478,7 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption) */ @Override - public void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option) { + public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option) { migrate(key, target, dbIndex, option, Long.MAX_VALUE); } @@ -486,7 +487,7 @@ class JedisClusterServerCommands implements RedisClusterServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption, long) */ @Override - public void migrate(final byte[] key, final RedisNode target, final int dbIndex, final MigrateOption option, + public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, final long timeout) { final int timeoutToUse = timeout <= Integer.MAX_VALUE ? (int) timeout : Integer.MAX_VALUE; 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 9d903b21c..6e4db6027 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 @@ -156,11 +156,11 @@ class JedisClusterZSetCommands implements RedisZSetCommands { byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); try { - if (limit != null) { - return JedisConverters.toTupleSet( - connection.getCluster().zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount())); + if (limit.isUnlimited()) { + return JedisConverters.toTupleSet(connection.getCluster().zrangeByScoreWithScores(key, min, max)); } - return JedisConverters.toTupleSet(connection.getCluster().zrangeByScoreWithScores(key, min, max)); + return JedisConverters.toTupleSet( + connection.getCluster().zrangeByScoreWithScores(key, min, max, limit.getOffset(), limit.getCount())); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -178,10 +178,10 @@ class JedisClusterZSetCommands implements RedisZSetCommands { byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); try { - if (limit != null) { - return connection.getCluster().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()); + if (limit.isUnlimited()) { + return connection.getCluster().zrevrangeByScore(key, max, min); } - return connection.getCluster().zrevrangeByScore(key, max, min); + return connection.getCluster().zrevrangeByScore(key, max, min, limit.getOffset(), limit.getCount()); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -200,11 +200,11 @@ class JedisClusterZSetCommands implements RedisZSetCommands { byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); try { - if (limit != null) { - return JedisConverters.toTupleSet( - connection.getCluster().zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount())); + if (limit.isUnlimited()) { + return JedisConverters.toTupleSet(connection.getCluster().zrevrangeByScoreWithScores(key, max, min)); } - return JedisConverters.toTupleSet(connection.getCluster().zrevrangeByScoreWithScores(key, max, min)); + return JedisConverters.toTupleSet( + connection.getCluster().zrevrangeByScoreWithScores(key, max, min, limit.getOffset(), limit.getCount())); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -262,10 +262,10 @@ class JedisClusterZSetCommands implements RedisZSetCommands { byte[] max = JedisConverters.boundaryToBytesForZRange(range.getMax(), JedisConverters.POSITIVE_INFINITY_BYTES); try { - if (limit != null) { - return connection.getCluster().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); + if (limit.isUnlimited()) { + return connection.getCluster().zrangeByScore(key, min, max); } - return connection.getCluster().zrangeByScore(key, min, max); + return connection.getCluster().zrangeByScore(key, min, max, limit.getOffset(), limit.getCount()); } catch (Exception ex) { throw convertJedisAccessException(ex); } @@ -279,15 +279,16 @@ class JedisClusterZSetCommands implements RedisZSetCommands { public Set zRangeByLex(byte[] key, Range range, Limit limit) { Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); + Assert.notNull(limit, "Limit must not be null!"); byte[] min = JedisConverters.boundaryToBytesForZRangeByLex(range.getMin(), JedisConverters.toBytes("-")); byte[] max = JedisConverters.boundaryToBytesForZRangeByLex(range.getMax(), JedisConverters.toBytes("+")); try { - if (limit != null) { - return connection.getCluster().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); + if (limit.isUnlimited()) { + return connection.getCluster().zrangeByLex(key, min, max); } - return connection.getCluster().zrangeByLex(key, min, max); + return connection.getCluster().zrangeByLex(key, min, max, limit.getOffset(), limit.getCount()); } catch (Exception ex) { throw convertJedisAccessException(ex); } 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 d1c7faaa0..de5df8c40 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 @@ -45,6 +45,7 @@ import org.springframework.data.redis.FallbackExceptionTranslationStrategy; import org.springframework.data.redis.RedisConnectionFailureException; import org.springframework.data.redis.connection.*; import org.springframework.data.redis.connection.convert.TransactionResultConverter; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; @@ -100,14 +101,14 @@ public class JedisConnection extends AbstractRedisConnection { private final Jedis jedis; private final Client client; - private Transaction transaction; + private @Nullable Transaction transaction; private final Pool pool; /** * flag indicating whether the connection needs to be dropped or not */ private boolean broken = false; - private volatile JedisSubscription subscription; - private volatile Pipeline pipeline; + private volatile @Nullable JedisSubscription subscription; + private volatile @Nullable Pipeline pipeline; private final int dbIndex; private final String clientName; private boolean convertPipelineAndTxResults = true; @@ -125,10 +126,13 @@ public class JedisConnection extends AbstractRedisConnection { @SuppressWarnings("unchecked") public Object get() { - if (convertPipelineAndTxResults && converter != null) { - return converter.convert(resultHolder.get()); + + Object raw = resultHolder.get(); + if (!convertPipelineAndTxResults || raw == null) { + return raw; } - return resultHolder.get(); + + return converter != null ? converter.convert(raw) : raw; } } @@ -594,10 +598,12 @@ public class JedisConnection extends AbstractRedisConnection { } } + @Nullable public Pipeline getPipeline() { return pipeline; } + @Nullable public Transaction getTransaction() { return transaction; } 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 e4c801ccf..ee340a4da 100644 --- a/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/jedis/JedisConnectionFactory.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.connection.jedis; +import org.springframework.lang.Nullable; import redis.clients.jedis.Client; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; @@ -91,16 +92,16 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, JedisConverters.exceptionConverter()); private final JedisClientConfiguration clientConfiguration; - private JedisShardInfo shardInfo; + private @Nullable JedisShardInfo shardInfo; private boolean providedShardInfo = false; - private Pool pool; + private @Nullable Pool pool; private boolean convertPipelineAndTxResults = true; private RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration("localhost", Protocol.DEFAULT_PORT); - private RedisSentinelConfiguration sentinelConfig; - private RedisClusterConfiguration clusterConfig; - private JedisCluster cluster; - private ClusterCommandExecutor clusterCommandExecutor; + private @Nullable RedisSentinelConfiguration sentinelConfig; + private @Nullable RedisClusterConfiguration clusterConfig; + private @Nullable JedisCluster cluster; + private @Nullable ClusterCommandExecutor clusterCommandExecutor; /** * Constructs a new JedisConnectionFactory instance with default settings (default connection pooling, no @@ -609,6 +610,7 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, * @deprecated since 2.0. */ @Deprecated + @Nullable public JedisShardInfo getShardInfo() { return shardInfo; } @@ -896,12 +898,12 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, static class MutableJedisClientConfiguration implements JedisClientConfiguration { private boolean useSsl; - private SSLSocketFactory sslSocketFactory; - private SSLParameters sslParameters; - private HostnameVerifier hostnameVerifier; + private @Nullable SSLSocketFactory sslSocketFactory; + private @Nullable SSLParameters sslParameters; + private @Nullable HostnameVerifier hostnameVerifier; private boolean usePooling = true; private GenericObjectPoolConfig poolConfig = new JedisPoolConfig(); - private String clientName; + private @Nullable String clientName; private Duration readTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT); private Duration connectTimeout = Duration.ofMillis(Protocol.DEFAULT_TIMEOUT); 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 a66303a83..e90a6361c 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 @@ -24,6 +24,7 @@ import org.springframework.data.redis.connection.ReturnType; import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; import org.springframework.data.redis.core.types.RedisClientInfo; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -453,7 +454,7 @@ class JedisServerCommands implements RedisServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption) */ @Override - public void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option) { + public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option) { migrate(key, target, dbIndex, option, Long.MAX_VALUE); } @@ -462,7 +463,7 @@ class JedisServerCommands implements RedisServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption, long) */ @Override - public void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option, long timeout) { + 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; 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 cc78a8197..2f523eb56 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 @@ -22,6 +22,7 @@ import java.util.concurrent.TimeUnit; import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.connection.jedis.JedisConnection.JedisResult; import org.springframework.data.redis.core.types.Expiration; +import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** @@ -114,9 +115,12 @@ class JedisStringCommands implements RedisStringCommands { @Override public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { - if (expiration == null || expiration.isPersistent()) { + Assert.notNull(expiration, "Expiration must not be null!"); + Assert.notNull(option, "Option must not be null!"); - if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { + if (expiration.isPersistent()) { + + if (ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { set(key, value); } else { @@ -143,7 +147,7 @@ class JedisStringCommands implements RedisStringCommands { } else { - if (option == null || ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { + if (ObjectUtils.nullSafeEquals(SetOption.UPSERT, option)) { if (ObjectUtils.nullSafeEquals(TimeUnit.MILLISECONDS, expiration.getTimeUnit())) { pSetEx(key, expiration.getExpirationTime(), value); 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 9bac91781..ad559c158 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 @@ -1,5 +1,5 @@ /** * Connection package for Jedis library. */ +@org.springframework.lang.NonNullApi package org.springframework.data.redis.connection.jedis; - diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java index 91d705c0a..8e4b29e8d 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java @@ -21,6 +21,8 @@ import io.lettuce.core.resource.ClientResources; import java.time.Duration; import java.util.Optional; +import org.springframework.lang.Nullable; + /** * Default implementation of {@literal LettuceClientConfiguration}. * @@ -39,7 +41,8 @@ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration { private final Duration shutdownTimeout; DefaultLettuceClientConfiguration(boolean useSsl, boolean verifyPeer, boolean startTls, - ClientResources clientResources, ClientOptions clientOptions, Duration timeout, Duration shutdownTimeout) { + @Nullable ClientResources clientResources, @Nullable ClientOptions clientOptions, Duration timeout, + Duration shutdownTimeout) { this.useSsl = useSsl; this.verifyPeer = verifyPeer; diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java index 7701a5e6a..7fffeae27 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePool.java @@ -31,6 +31,7 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.redis.connection.PoolException; import org.springframework.data.redis.connection.RedisSentinelConfiguration; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -46,16 +47,16 @@ import org.springframework.util.StringUtils; public class DefaultLettucePool implements LettucePool, InitializingBean { @SuppressWarnings("rawtypes") // - private GenericObjectPool> internalPool; - private RedisClient client; + private @Nullable GenericObjectPool> internalPool; + private @Nullable RedisClient client; private int dbIndex = 0; private GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); private String hostName = "localhost"; private int port = 6379; - private String password; + private @Nullable String password; private long timeout = TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS); - private RedisSentinelConfiguration sentinelConfiguration; - private ClientResources clientResources; + private @Nullable RedisSentinelConfiguration sentinelConfiguration; + private @Nullable ClientResources clientResources; /** * Constructs a new DefaultLettucePool instance with default settings. @@ -128,8 +129,7 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { private RedisURI getRedisURI() { RedisURI redisUri = isRedisSentinelAware() - ? LettuceConverters.sentinelConfigurationToRedisURI(sentinelConfiguration) - : createSimpleHostRedisURI(); + ? LettuceConverters.sentinelConfigurationToRedisURI(sentinelConfiguration) : createSimpleHostRedisURI(); if (StringUtils.hasText(password)) { redisUri.setPassword(password); @@ -202,6 +202,8 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { /** * @return The Redis client */ + @Override + @Nullable public RedisClient getClient() { return client; } @@ -244,6 +246,7 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { * * @return password for authentication */ + @Nullable public String getPassword() { return password; } @@ -317,6 +320,7 @@ public class DefaultLettucePool implements LettucePool, InitializingBean { * @return {@literal null} if not set. * @since 1.7 */ + @Nullable public ClientResources getClientResources() { return clientResources; } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java index b3f556bd0..7a3ba0e08 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java @@ -23,6 +23,7 @@ import java.time.Duration; import java.util.Optional; import java.util.concurrent.TimeUnit; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -129,8 +130,8 @@ public interface LettuceClientConfiguration { boolean useSsl; boolean verifyPeer = true; boolean startTls; - ClientResources clientResources; - ClientOptions clientOptions; + @Nullable ClientResources clientResources; + @Nullable ClientOptions clientOptions; Duration timeout = Duration.ofSeconds(RedisURI.DEFAULT_TIMEOUT); Duration shutdownTimeout = Duration.ofMillis(100); 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 d93f398c2..7073e0fe4 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 @@ -36,6 +36,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.ExceptionTranslationStrategy; import org.springframework.data.redis.PassThroughExceptionTranslationStrategy; @@ -45,6 +46,7 @@ import org.springframework.data.redis.connection.ClusterCommandExecutor.MultiKey import org.springframework.data.redis.connection.ClusterCommandExecutor.NodeResult; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; import org.springframework.data.redis.connection.convert.Converters; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -608,7 +610,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau static class LettuceClusterNodeResourceProvider implements ClusterNodeResourceProvider, DisposableBean { private final LettuceConnectionProvider connectionProvider; - private volatile StatefulRedisClusterConnection connection; + private volatile @Nullable StatefulRedisClusterConnection connection; @Override @SuppressWarnings("unchecked") @@ -627,12 +629,7 @@ public class LettuceClusterConnection extends LettuceConnection implements Defau try { return connection.getConnection(node.getHost(), node.getPort()).sync(); } catch (RedisException e) { - - // unwrap cause when cluster node not known in cluster - if (e.getCause() instanceof IllegalArgumentException) { - throw (IllegalArgumentException) e.getCause(); - } - throw e; + throw new DataAccessResourceFailureException(e.getMessage(), e); } } 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 f50ce9fa7..7a0d412f4 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 @@ -66,6 +66,7 @@ import org.springframework.data.redis.connection.convert.TransactionResultConver import org.springframework.data.redis.connection.lettuce.LettuceConnectionProvider.TargetAware; import org.springframework.data.redis.core.RedisCommand; import org.springframework.data.redis.core.ScanOptions; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -95,7 +96,7 @@ public class LettuceConnection extends AbstractRedisConnection { private final LettuceConnectionProvider connectionProvider; private final StatefulConnection asyncSharedConn; - private StatefulConnection asyncDedicatedConn; + private @Nullable StatefulConnection asyncDedicatedConn; private final long timeout; @@ -103,9 +104,9 @@ public class LettuceConnection extends AbstractRedisConnection { private boolean isClosed = false; private boolean isMulti = false; private boolean isPipelined = false; - private List ppline; + private @Nullable List ppline; private Queue> txResults = new LinkedList<>(); - private volatile LettuceSubscription subscription; + private volatile @Nullable LettuceSubscription subscription; /** flag indicating whether the connection needs to be dropped or not */ private boolean convertPipelineAndTxResults = true; diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index 3ecb738e8..9c93cd6d1 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -42,6 +42,7 @@ import org.springframework.data.redis.ExceptionTranslationStrategy; import org.springframework.data.redis.PassThroughExceptionTranslationStrategy; import org.springframework.data.redis.RedisConnectionFailureException; import org.springframework.data.redis.connection.*; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -81,20 +82,20 @@ public class LettuceConnectionFactory private final Log log = LogFactory.getLog(getClass()); private final LettuceClientConfiguration clientConfiguration; - private AbstractRedisClient client; - private LettuceConnectionProvider connectionProvider; - private LettuceConnectionProvider reactiveConnectionProvider; + private @Nullable AbstractRedisClient client; + private @Nullable LettuceConnectionProvider connectionProvider; + private @Nullable LettuceConnectionProvider reactiveConnectionProvider; private boolean validateConnection = false; private boolean shareNativeConnection = true; - private StatefulRedisConnection connection; - private LettucePool pool; + private @Nullable StatefulRedisConnection connection; + private @Nullable LettucePool pool; /** Synchronization monitor for the shared Connection */ private final Object connectionMonitor = new Object(); private boolean convertPipelineAndTxResults = true; private RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration("localhost", 6379); - private RedisSentinelConfiguration sentinelConfiguration; - private RedisClusterConfiguration clusterConfiguration; - private ClusterCommandExecutor clusterCommandExecutor; + private @Nullable RedisSentinelConfiguration sentinelConfiguration; + private @Nullable RedisClusterConfiguration clusterConfiguration; + private @Nullable ClusterCommandExecutor clusterCommandExecutor; /** * Constructs a new {@link LettuceConnectionFactory} instance with default settings. @@ -697,6 +698,7 @@ public class LettuceConnectionFactory * @return the {@link RedisStandaloneConfiguration}, may be {@literal null}. * @since 2.0 */ + @Nullable public RedisSentinelConfiguration getSentinelConfiguration() { return sentinelConfiguration; } @@ -705,6 +707,7 @@ public class LettuceConnectionFactory * @return the {@link RedisClusterConfiguration}, may be {@literal null}. * @since 2.0 */ + @Nullable public RedisClusterConfiguration getClusterConfiguration() { return clusterConfiguration; } @@ -893,7 +896,7 @@ public class LettuceConnectionFactory private boolean useSsl; private boolean verifyPeer = true; private boolean startTls; - private ClientResources clientResources; + private @Nullable ClientResources clientResources; private Duration timeout = Duration.ofSeconds(RedisURI.DEFAULT_TIMEOUT); private Duration shutdownTimeout = Duration.ofMillis(100); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java index 48f0cb42b..3d0254bb0 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConverters.java @@ -60,6 +60,7 @@ import org.springframework.data.redis.connection.convert.StringToRedisClientInfo import org.springframework.data.redis.core.types.Expiration; import org.springframework.data.redis.core.types.RedisClientInfo; 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; @@ -721,7 +722,7 @@ abstract public class LettuceConverters extends Converters { * @param option can be {@literal null}. * @since 1.7 */ - public static SetArgs toSetArgs(Expiration expiration, SetOption option) { + public static SetArgs toSetArgs(@Nullable Expiration expiration, @Nullable SetOption option) { SetArgs args = new SetArgs(); if (expiration != null && !expiration.isPersistent()) { diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java index f60a1eb51..a6023441b 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettucePool.java @@ -19,6 +19,7 @@ import io.lettuce.core.AbstractRedisClient; import io.lettuce.core.api.StatefulConnection; import org.springframework.data.redis.connection.Pool; +import org.springframework.lang.Nullable; /** * Pool of Lettuce {@link StatefulConnection}s @@ -34,6 +35,7 @@ public interface LettucePool extends Pool> { /** * @return The {@link AbstractRedisClient} used to create pooled connections */ + @Nullable AbstractRedisClient getClient(); } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java index feb4837b2..0a5ba80c0 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveStringCommands.java @@ -317,7 +317,8 @@ class LettuceReactiveStringCommands implements ReactiveStringCommands { Assert.notNull(command.getKey(), "Key must not be null!"); Range range = command.getRange(); - return (range != null ? cmd.bitcount(command.getKey(), range.getLowerBound().getValue().orElse(null), + + return (!Range.unbounded().equals(range) ? cmd.bitcount(command.getKey(), range.getLowerBound().getValue().orElse(null), range.getUpperBound().getValue().orElse(null)) : cmd.bitcount(command.getKey())) .map(responseValue -> new NumericResponse<>(command, responseValue)); })); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java index 117bb7844..33d7d8252 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceReactiveZSetCommands.java @@ -229,7 +229,7 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands { Assert.notNull(command.getKey(), "Key must not be null!"); Assert.notNull(command.getRange(), "Range must not be null!"); - boolean isLimited = command.getLimit().isPresent(); + boolean isLimited = command.getLimit().isPresent() && !command.getLimit().get().isUnlimited(); Publisher result; @@ -445,7 +445,7 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands { Flux result; - if (command.getLimit() != null) { + if (!command.getLimit().isUnlimited()) { if (ObjectUtils.nullSafeEquals(command.getDirection(), Direction.ASC)) { result = cmd.zrangebylex(command.getKey(), ArgumentConverters.toRange(command.getRange()), diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java index ddf1636fe..5b7541ce5 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceSentinelConnection.java @@ -44,7 +44,7 @@ public class LettuceSentinelConnection implements RedisSentinelConnection { LettuceConverters.exceptionConverter()); private final LettuceConnectionProvider provider; - private StatefulRedisSentinelConnection connection; + private StatefulRedisSentinelConnection connection; // no that should not be null /** * Creates a {@link LettuceSentinelConnection} with a dedicated client for a supplied {@link RedisNode}. 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 7cd93a421..97f68d210 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 @@ -28,6 +28,7 @@ import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; import org.springframework.data.redis.core.types.RedisClientInfo; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -494,7 +495,7 @@ class LettuceServerCommands implements RedisServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption) */ @Override - public void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option) { + public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option) { migrate(key, target, dbIndex, option, Long.MAX_VALUE); } @@ -503,7 +504,7 @@ class LettuceServerCommands implements RedisServerCommands { * @see org.springframework.data.redis.connection.RedisServerCommands#migrate(byte[], org.springframework.data.redis.connection.RedisNode, int, org.springframework.data.redis.connection.RedisServerCommands.MigrateOption, long) */ @Override - public void migrate(byte[] key, RedisNode target, int dbIndex, MigrateOption option, long timeout) { + public void migrate(byte[] key, RedisNode target, int dbIndex, @Nullable MigrateOption option, long timeout) { try { if (isPipelined()) { 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 79260171a..4966281fb 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 @@ -27,6 +27,7 @@ import org.springframework.data.redis.connection.RedisStringCommands; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceResult; import org.springframework.data.redis.connection.lettuce.LettuceConnection.LettuceTxResult; import org.springframework.data.redis.core.types.Expiration; +import org.springframework.util.Assert; /** * @author Christoph Strobl @@ -80,6 +81,9 @@ class LettuceStringCommands implements RedisStringCommands { @Override public void set(byte[] key, byte[] value, Expiration expiration, SetOption option) { + Assert.notNull(expiration, "Expiration must not be null!"); + Assert.notNull(option, "Option must not be null!"); + try { if (isPipelined()) { pipeline(connection.newLettuceStatusResult( 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 7b5409837..d2cb7e3f7 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 @@ -259,36 +259,37 @@ class LettuceZSetCommands implements RedisZSetCommands { 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 != null) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscore(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } else { + 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 != null) { - transaction(connection.newLettuceTxResult( - getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.bytesListToBytesSet())); - } else { + 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 != null) { - return LettuceConverters.toBytesSet( - getConnection().zrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + if (limit.isUnlimited()) { + return LettuceConverters.toBytesSet(getConnection().zrangebyscore(key, LettuceConverters.toRange(range))); } - 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); } @@ -302,38 +303,39 @@ class LettuceZSetCommands implements RedisZSetCommands { public Set zRangeByScoreWithScores(byte[] key, Range range, Limit limit) { Assert.notNull(range, "Range for ZRANGEBYSCOREWITHSCORES must not be null!"); + Assert.notNull(limit, "Limit must not be null!"); try { if (isPipelined()) { - if (limit != null) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.scoredValuesToTupleSet())); - } else { + if (limit.isUnlimited()) { pipeline(connection.newLettuceResult( getAsyncConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range)), LettuceConverters.scoredValuesToTupleSet())); + } else { + pipeline(connection.newLettuceResult(getAsyncConnection().zrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.scoredValuesToTupleSet())); } return null; } if (isQueueing()) { - if (limit != null) { - transaction(connection.newLettuceTxResult(getConnection().zrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.scoredValuesToTupleSet())); - } else { + if (limit.isUnlimited()) { transaction(connection.newLettuceTxResult( getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range)), LettuceConverters.scoredValuesToTupleSet())); + } else { + transaction(connection.newLettuceTxResult(getConnection().zrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.scoredValuesToTupleSet())); } return null; } - if (limit != null) { - return LettuceConverters.toTupleSet(getConnection().zrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + if (limit.isUnlimited()) { + return LettuceConverters + .toTupleSet(getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range))); } - return LettuceConverters - .toTupleSet(getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range))); + return LettuceConverters.toTupleSet(getConnection().zrangebyscoreWithScores(key, LettuceConverters.toRange(range), + LettuceConverters.toLimit(limit))); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -370,37 +372,38 @@ class LettuceZSetCommands implements RedisZSetCommands { public Set zRevRangeByScore(byte[] key, Range range, Limit limit) { Assert.notNull(range, "Range for ZREVRANGEBYSCORE must not be null!"); + Assert.notNull(limit, "Limit must not be null!"); try { if (isPipelined()) { - if (limit != null) { - pipeline( - connection.newLettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), - LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); - } else { + if (limit.isUnlimited()) { pipeline( connection.newLettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range)), LettuceConverters.bytesListToBytesSet())); + } else { + pipeline( + connection.newLettuceResult(getAsyncConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), + LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); } return null; } if (isQueueing()) { - if (limit != null) { - transaction(connection.newLettuceTxResult( - getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.bytesListToBytesSet())); - } else { + if (limit.isUnlimited()) { transaction( connection.newLettuceTxResult(getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range)), LettuceConverters.bytesListToBytesSet())); + } else { + transaction(connection.newLettuceTxResult( + getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.bytesListToBytesSet())); } return null; } - if (limit != null) { - return LettuceConverters.toBytesSet( - getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + if (limit.isUnlimited()) { + return LettuceConverters.toBytesSet(getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range))); } - return LettuceConverters.toBytesSet(getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range))); + return LettuceConverters.toBytesSet( + getConnection().zrevrangebyscore(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -414,38 +417,39 @@ class LettuceZSetCommands implements RedisZSetCommands { public Set zRevRangeByScoreWithScores(byte[] key, Range range, Limit limit) { Assert.notNull(range, "Range for ZREVRANGEBYSCOREWITHSCORES must not be null!"); + Assert.notNull(limit, "Limit must not be null!"); try { if (isPipelined()) { - if (limit != null) { - pipeline(connection.newLettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.scoredValuesToTupleSet())); - } else { + if (limit.isUnlimited()) { pipeline(connection.newLettuceResult( getAsyncConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range)), LettuceConverters.scoredValuesToTupleSet())); + } else { + pipeline(connection.newLettuceResult(getAsyncConnection().zrevrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.scoredValuesToTupleSet())); } return null; } if (isQueueing()) { - if (limit != null) { - transaction(connection.newLettuceTxResult(getConnection().zrevrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), - LettuceConverters.scoredValuesToTupleSet())); - } else { + if (limit.isUnlimited()) { transaction(connection.newLettuceTxResult( getConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range)), LettuceConverters.scoredValuesToTupleSet())); + } else { + transaction(connection.newLettuceTxResult(getConnection().zrevrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + LettuceConverters.scoredValuesToTupleSet())); } return null; } - if (limit != null) { - return LettuceConverters.toTupleSet(getConnection().zrevrangebyscoreWithScores(key, - LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + if (limit.isUnlimited()) { + return LettuceConverters + .toTupleSet(getConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range))); } - return LettuceConverters - .toTupleSet(getConnection().zrevrangebyscoreWithScores(key, LettuceConverters.toRange(range))); + return LettuceConverters.toTupleSet(getConnection().zrevrangebyscoreWithScores(key, + LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); } catch (Exception ex) { throw convertLettuceAccessException(ex); } @@ -751,38 +755,39 @@ class LettuceZSetCommands implements RedisZSetCommands { public Set zRangeByLex(byte[] key, Range range, Limit limit) { Assert.notNull(range, "Range cannot be null for ZRANGEBYLEX."); + Assert.notNull(limit, "Limit must not be null!"); try { if (isPipelined()) { - if (limit != null) { - pipeline(connection.newLettuceResult( - getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + if (limit.isUnlimited()) { + pipeline(connection.newLettuceResult(getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range)), LettuceConverters.bytesListToBytesSet())); } else { - pipeline(connection.newLettuceResult(getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range)), + pipeline(connection.newLettuceResult( + getAsyncConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); } return null; } if (isQueueing()) { - if (limit != null) { - transaction(connection.newLettuceTxResult( - getConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), + if (limit.isUnlimited()) { + transaction(connection.newLettuceTxResult(getConnection().zrangebylex(key, LettuceConverters.toRange(range)), LettuceConverters.bytesListToBytesSet())); } else { - transaction(connection.newLettuceTxResult(getConnection().zrangebylex(key, LettuceConverters.toRange(range)), + transaction(connection.newLettuceTxResult( + getConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit)), LettuceConverters.bytesListToBytesSet())); } return null; } - if (limit != null) { - return LettuceConverters.bytesListToBytesSet().convert( - getConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); + if (limit.isUnlimited()) { + return LettuceConverters.bytesListToBytesSet() + .convert(getConnection().zrangebylex(key, LettuceConverters.toRange(range))); } + return LettuceConverters.bytesListToBytesSet().convert( + getConnection().zrangebylex(key, LettuceConverters.toRange(range), LettuceConverters.toLimit(limit))); - return LettuceConverters.bytesListToBytesSet() - .convert(getConnection().zrangebylex(key, LettuceConverters.toRange(range))); } catch (Exception ex) { throw convertLettuceAccessException(ex); } 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 5f69d43da..f8b09f070 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 @@ -1,5 +1,5 @@ /** - * Connection package for Lettuce Redis client. + * Connection package for Lettuce Redis client. */ +@org.springframework.lang.NonNullApi 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 fa07c3cf8..4c78de6fc 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 @@ -4,5 +4,6 @@ * *

Performs exception translation between the underlying library exceptions to Spring's DAO hierarchy. */ +@org.springframework.lang.NonNullApi package org.springframework.data.redis.connection; diff --git a/src/main/java/org/springframework/data/redis/connection/util/AbstractSubscription.java b/src/main/java/org/springframework/data/redis/connection/util/AbstractSubscription.java index f6f947d3b..7d58b7e6c 100644 --- a/src/main/java/org/springframework/data/redis/connection/util/AbstractSubscription.java +++ b/src/main/java/org/springframework/data/redis/connection/util/AbstractSubscription.java @@ -22,6 +22,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisInvalidSubscriptionException; import org.springframework.data.redis.connection.Subscription; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -30,6 +31,7 @@ import org.springframework.util.ObjectUtils; * the actual registration/unregistration. * * @author Costin Leau + * @author Christoph Strobl */ public abstract class AbstractSubscription implements Subscription { @@ -47,12 +49,14 @@ public abstract class AbstractSubscription implements Subscription { * subscription w/o triggering a subscription action (as some clients (Jedis) require an initial call before entering * into listening mode). * - * @param listener - * @param channels - * @param patterns + * @param listener must not be {@literal null}. + * @param channels can be {@literal null}. + * @param patterns can be {@literal null}. */ - protected AbstractSubscription(MessageListener listener, byte[][] channels, byte[][] patterns) { + protected AbstractSubscription(MessageListener listener, @Nullable byte[][] channels, @Nullable byte[][] patterns) { + Assert.notNull(listener, "MessageListener must not be null!"); + this.listener = listener; synchronized (this.channels) { @@ -146,7 +150,7 @@ public abstract class AbstractSubscription implements Subscription { unsubscribe((byte[][]) null); } - public void pUnsubscribe(byte[]... patts) { + public void pUnsubscribe(@Nullable byte[]... patts) { if (!isAlive()) { return; } @@ -173,7 +177,7 @@ public abstract class AbstractSubscription implements Subscription { closeIfUnsubscribed(); } - public void unsubscribe(byte[]... chans) { + public void unsubscribe(@Nullable byte[]... chans) { if (!isAlive()) { return; } @@ -225,7 +229,7 @@ public abstract class AbstractSubscription implements Subscription { return list; } - private static void add(Collection col, byte[]... bytes) { + private static void add(Collection col, @Nullable byte[]... bytes) { if (!ObjectUtils.isEmpty(bytes)) { for (byte[] bs : bytes) { col.add(new ByteArrayWrapper(bs)); @@ -233,7 +237,7 @@ public abstract class AbstractSubscription implements Subscription { } } - private static void remove(Collection col, byte[]... bytes) { + private static void remove(Collection col, @Nullable byte[]... bytes) { if (!ObjectUtils.isEmpty(bytes)) { for (byte[] bs : bytes) { col.remove(new ByteArrayWrapper(bs)); diff --git a/src/main/java/org/springframework/data/redis/connection/util/Base64.java b/src/main/java/org/springframework/data/redis/connection/util/Base64.java index c37f8b69d..4f1110662 100644 --- a/src/main/java/org/springframework/data/redis/connection/util/Base64.java +++ b/src/main/java/org/springframework/data/redis/connection/util/Base64.java @@ -2,6 +2,8 @@ package org.springframework.data.redis.connection.util; import java.util.Arrays; +import org.springframework.lang.Nullable; + /** * A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance with RFC 2045.
*
@@ -12,7 +14,8 @@ import java.util.Arrays; * On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 Codec for encode and about 50% faster for * decoding large arrays. This implementation is about twice as fast on very small arrays (< 30 bytes). If * source/destination is a String this version is about three times as fast due to the fact that the - * Commons Codec result has to be recoded to a String from byte[], which is very expensive.
+ * Commons Codec result has to be recoded to a String from byte[], which is very + * expensive.
*
* This encode/decode algorithm doesn't create any temporary arrays as many other codecs do, it only allocates the * resulting array. This produces less garbage and it is possible to handle arrays twice as large as algorithms that @@ -76,7 +79,7 @@ class Base64 { * faster. * @return A BASE64 encoded array. Never null. */ - public final static char[] encodeToChar(byte[] sArr, boolean lineSep) { + public final static char[] encodeToChar(@Nullable byte[] sArr, boolean lineSep) { // Check special case int sLen = sArr != null ? sArr.length : 0; if (sLen == 0) @@ -129,7 +132,8 @@ class Base64 { * @return The decoded array of bytes. May be of length 0. Will be null if the legal characters * (including '=') isn't divideable by 4. (I.e. definitely corrupted). */ - public final static byte[] decode(char[] sArr) { + @Nullable + public final static byte[] decode(@Nullable char[] sArr) { // Check special case int sLen = sArr != null ? sArr.length : 0; if (sLen == 0) @@ -256,7 +260,7 @@ class Base64 { * faster. * @return A BASE64 encoded array. Never null. */ - public final static byte[] encodeToByte(byte[] sArr, boolean lineSep) { + public final static byte[] encodeToByte(@Nullable byte[] sArr, boolean lineSep) { // Check special case int sLen = sArr != null ? sArr.length : 0; if (sLen == 0) @@ -309,6 +313,7 @@ class Base64 { * @return The decoded array of bytes. May be of length 0. Will be null if the legal characters * (including '=') isn't divideable by 4. (I.e. definitely corrupted). */ + @Nullable public final static byte[] decode(byte[] sArr) { // Check special case int sLen = sArr.length; @@ -451,7 +456,8 @@ class Base64 { * @return The decoded array of bytes. May be of length 0. Will be null if the legal characters * (including '=') isn't divideable by 4. (I.e. definitely corrupted). */ - public final static byte[] decode(String str) { + @Nullable + public final static byte[] decode(@Nullable String str) { // Check special case int sLen = str != null ? str.length() : 0; if (sLen == 0) diff --git a/src/main/java/org/springframework/data/redis/connection/util/DecodeUtils.java b/src/main/java/org/springframework/data/redis/connection/util/DecodeUtils.java index 9b7a2fa65..d853fbc9e 100644 --- a/src/main/java/org/springframework/data/redis/connection/util/DecodeUtils.java +++ b/src/main/java/org/springframework/data/redis/connection/util/DecodeUtils.java @@ -23,10 +23,13 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.springframework.lang.Nullable; + /** * Simple class containing various decoding utilities. * * @author Costin Leau + * @auhtor Christoph Strobl */ public abstract class DecodeUtils { @@ -42,7 +45,8 @@ public abstract class DecodeUtils { return result; } - public static byte[] encode(String string) { + @Nullable + public static byte[] encode(@Nullable String string) { return (string == null ? null : Base64.decode(string)); } 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 e24d76afa..05f261de6 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 @@ -1,5 +1,6 @@ /** * Internal utility package for encoding/decoding Strings to byte[] (using Base64) library. */ +@org.springframework.lang.NonNullApi 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 19e3b0153..442f83762 100644 --- a/src/main/java/org/springframework/data/redis/core/AbstractOperations.java +++ b/src/main/java/org/springframework/data/redis/core/AbstractOperations.java @@ -32,6 +32,7 @@ import org.springframework.data.redis.connection.convert.Converters; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationUtils; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -88,6 +89,7 @@ abstract class AbstractOperations { return template.getStringSerializer(); } + @Nullable T execute(RedisCallback callback, boolean b) { return template.execute(callback, b); } @@ -282,8 +284,9 @@ abstract class AbstractOperations { } @SuppressWarnings("unchecked") - Map deserializeHashMap(Map entries) { + 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/BoundGeoOperations.java b/src/main/java/org/springframework/data/redis/core/BoundGeoOperations.java index e32a2d18b..b2bbccfa6 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundGeoOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundGeoOperations.java @@ -25,6 +25,7 @@ import org.springframework.data.geo.Metric; import org.springframework.data.geo.Point; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; +import org.springframework.lang.Nullable; /** * {@link GeoOperations} bound to a certain key. @@ -41,10 +42,11 @@ public interface BoundGeoOperations extends BoundKeyOperations { * * @param point must not be {@literal null}. * @param member must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOADD */ + @Nullable Long add(Point point, M member); /** @@ -52,11 +54,12 @@ public interface BoundGeoOperations extends BoundKeyOperations { * * @param point must not be {@literal null}. * @param member must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD * @deprecated since 2.0, use {@link #add(Point, Object)}. */ @Deprecated + @Nullable default Long geoAdd(Point point, M member) { return add(point, member); } @@ -65,21 +68,23 @@ public interface BoundGeoOperations extends BoundKeyOperations { * Add {@link GeoLocation} to {@literal key}. * * @param location must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOADD */ + @Nullable Long add(GeoLocation location); /** * Add {@link GeoLocation} to {@literal key}. * * @param location must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD * @deprecated since 2.0, use {@link #add(GeoLocation)}. */ @Deprecated + @Nullable default Long geoAdd(GeoLocation location) { return add(location); } @@ -88,21 +93,23 @@ public interface BoundGeoOperations extends BoundKeyOperations { * Add {@link Map} of member / {@link Point} pairs to {@literal key}. * * @param memberCoordinateMap must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOADD */ + @Nullable Long add(Map memberCoordinateMap); /** * Add {@link Map} of member / {@link Point} pairs to {@literal key}. * * @param memberCoordinateMap must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD * @deprecated since 2.0, use {@link #add(Map)}. */ @Deprecated + @Nullable default Long geoAdd(Map memberCoordinateMap) { return add(memberCoordinateMap); } @@ -111,21 +118,23 @@ public interface BoundGeoOperations extends BoundKeyOperations { * Add {@link GeoLocation}s to {@literal key} * * @param locations must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOADD */ + @Nullable Long add(Iterable> locations); /** * Add {@link GeoLocation}s to {@literal key} * * @param locations must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD * @deprecated since 2.0, use {@link #add(Iterable)}. */ @Deprecated + @Nullable default Long geoAdd(Iterable> locations) { return add(locations); } @@ -139,6 +148,7 @@ public interface BoundGeoOperations extends BoundKeyOperations { * @since 2.0 * @see Redis Documentation: GEODIST */ + @Nullable Distance distance(M member1, M member2); /** @@ -151,6 +161,7 @@ public interface BoundGeoOperations extends BoundKeyOperations { * @deprecated since 2.0, use {@link #distance(Object, Object)}. */ @Deprecated + @Nullable default Distance geoDist(M member1, M member2) { return distance(member1, member2); } @@ -165,6 +176,7 @@ public interface BoundGeoOperations extends BoundKeyOperations { * @since 2.0 * @see Redis Documentation: GEODIST */ + @Nullable Distance distance(M member1, M member2, Metric metric); /** @@ -178,6 +190,7 @@ public interface BoundGeoOperations extends BoundKeyOperations { * @deprecated since 2.0, use {@link #distance(Object, Object, Metric)}. */ @Deprecated + @Nullable default Distance geoDist(M member1, M member2, Metric metric) { return distance(member1, member2, metric); } @@ -186,21 +199,23 @@ public interface BoundGeoOperations extends BoundKeyOperations { * Get Geohash representation of the position for one or more {@literal member}s. * * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOHASH */ + @Nullable List hash(M... members); /** * Get Geohash representation of the position for one or more {@literal member}s. * * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEOHASH * @deprecated since 2.0, use {@link #hash(Object[])}. */ @Deprecated + @Nullable default List geoHash(M... members) { return hash(members); } @@ -209,21 +224,23 @@ public interface BoundGeoOperations extends BoundKeyOperations { * Get the {@link Point} representation of positions for one or more {@literal member}s. * * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOPOS */ + @Nullable List position(M... members); /** * Get the {@link Point} representation of positions for one or more {@literal member}s. * * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEOPOS * @deprecated since 2.0, use {@link #position(Object[])}. */ @Deprecated + @Nullable default List geoPos(M... members) { return position(members); } @@ -232,21 +249,23 @@ public interface BoundGeoOperations extends BoundKeyOperations { * Get the {@literal member}s within the boundaries of a given {@link Circle}. * * @param within must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUS */ + @Nullable GeoResults> radius(Circle within); /** * Get the {@literal member}s within the boundaries of a given {@link Circle}. * * @param within must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUS * @deprecated since 2.0, use {@link #radius(Circle)}. */ @Deprecated + @Nullable default GeoResults> geoRadius(Circle within) { return radius(within); } @@ -256,10 +275,11 @@ public interface BoundGeoOperations extends BoundKeyOperations { * * @param within must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUS */ + @Nullable GeoResults> radius(Circle within, GeoRadiusCommandArgs args); /** @@ -267,11 +287,12 @@ public interface BoundGeoOperations extends BoundKeyOperations { * * @param within must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUS * @deprecated since 2.0, use {@link #radius(Circle, GeoRadiusCommandArgs)}. */ @Deprecated + @Nullable default GeoResults> geoRadius(Circle within, GeoRadiusCommandArgs args) { return radius(within, args); } @@ -282,10 +303,11 @@ public interface BoundGeoOperations extends BoundKeyOperations { * * @param member must not be {@literal null}. * @param radius - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUSBYMEMBER */ + @Nullable GeoResults> radius(K key, M member, double radius); /** @@ -294,11 +316,12 @@ public interface BoundGeoOperations extends BoundKeyOperations { * * @param member must not be {@literal null}. * @param radius - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUSBYMEMBER * @deprecated since 2.0, use {@link #radius(Object, Object, double)}. */ @Deprecated + @Nullable default GeoResults> geoRadiusByMember(K key, M member, double radius) { return radius(key, member, radius); } @@ -309,10 +332,11 @@ public interface BoundGeoOperations extends BoundKeyOperations { * * @param member must not be {@literal null}. * @param distance must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUSBYMEMBER */ + @Nullable GeoResults> radius(M member, Distance distance); /** @@ -321,11 +345,12 @@ public interface BoundGeoOperations extends BoundKeyOperations { * * @param member must not be {@literal null}. * @param distance must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUSBYMEMBER * @deprecated since 2.0, use {@link #radius(Object, Distance)}. */ @Deprecated + @Nullable default GeoResults> geoRadiusByMember(M member, Distance distance) { return radius(member, distance); } @@ -337,10 +362,11 @@ public interface BoundGeoOperations extends BoundKeyOperations { * @param member must not be {@literal null}. * @param distance must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUSBYMEMBER */ + @Nullable GeoResults> radius(M member, Distance distance, GeoRadiusCommandArgs args); /** @@ -350,11 +376,12 @@ public interface BoundGeoOperations extends BoundKeyOperations { * @param member must not be {@literal null}. * @param distance must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUSBYMEMBER * @deprecated since 2.0, use {@link #radius(Object, Distance, GeoRadiusCommandArgs)}. */ @Deprecated + @Nullable default GeoResults> geoRadiusByMember(M member, Distance distance, GeoRadiusCommandArgs args) { return radius(member, distance, args); } @@ -363,19 +390,21 @@ public interface BoundGeoOperations extends BoundKeyOperations { * Remove the {@literal member}s. * * @param members must not be {@literal null}. - * @return Number of elements removed. + * @return Number of elements removed. {@literal null} when used in pipeline / transaction. * @since 2.0 */ + @Nullable Long remove(M... members); /** * Remove the {@literal member}s. * * @param members must not be {@literal null}. - * @return Number of elements removed. + * @return Number of elements removed. {@literal null} when used in pipeline / transaction. * @deprecated since 2.0, use {@link #remove(Object[])}. */ @Deprecated + @Nullable default Long geoRemove(M... members) { return remove(members); } diff --git a/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java b/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java index 8c39ce643..b4a4a9015 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.springframework.lang.Nullable; + /** * Hash operations bound to a certain key. * @@ -34,32 +36,36 @@ public interface BoundHashOperations extends BoundKeyOperations { * Delete given hash {@code keys} at the bound key. * * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Long delete(Object... keys); /** * Determine if given hash {@code key} exists at the bound key. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Boolean hasKey(Object key); /** * Get value for given {@code key} from the hash at the bound key. * - * @param key must not be {@literal null}. - * @return + * @param member must not be {@literal null}. + * @return {@literal null} when member does not exist or when used in pipeline / transaction. */ - HV get(Object key); + @Nullable + HV get(Object member); /** * Get values for given {@code keys} from the hash at the bound key. * * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable List multiGet(Collection keys); /** @@ -67,8 +73,9 @@ public interface BoundHashOperations extends BoundKeyOperations { * * @param key must not be {@literal null}. * @param delta - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Long increment(HK key, long delta); /** @@ -76,22 +83,25 @@ public interface BoundHashOperations extends BoundKeyOperations { * * @param key must not be {@literal null}. * @param delta - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Double increment(HK key, double delta); /** * Get key set (fields) of hash at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Set keys(); /** * Get size of hash at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Long size(); /** @@ -114,22 +124,25 @@ public interface BoundHashOperations extends BoundKeyOperations { * * @param key must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Boolean putIfAbsent(HK key, HV value); /** * Get entry set (values) of hash at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable List values(); /** * Get entire hash at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Map entries(); /** @@ -142,7 +155,7 @@ public interface BoundHashOperations extends BoundKeyOperations { Cursor> scan(ScanOptions options); /** - * @return + * @return never {@literal null}. */ RedisOperations getOperations(); } diff --git a/src/main/java/org/springframework/data/redis/core/BoundKeyOperations.java b/src/main/java/org/springframework/data/redis/core/BoundKeyOperations.java index 088bd39d0..961b93a9f 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundKeyOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundKeyOperations.java @@ -19,6 +19,7 @@ import java.util.Date; import java.util.concurrent.TimeUnit; import org.springframework.data.redis.connection.DataType; +import org.springframework.lang.Nullable; /** * Operations over a Redis key. Useful for executing common key-'bound' operations to all implementations. @@ -35,54 +36,59 @@ public interface BoundKeyOperations { /** * Returns the key associated with this entity. - * + * * @return key associated with the implementing entity */ K getKey(); /** * Returns the associated Redis type. - * - * @return key type + * + * @return key type. {@literal null} when used in pipeline / transaction. */ + @Nullable DataType getType(); /** * Returns the expiration of this key. - * - * @return expiration value (in seconds) + * + * @return expiration value (in seconds). {@literal null} when used in pipeline / transaction. */ + @Nullable Long getExpire(); /** * Sets the key time-to-live/expiration. - * + * * @param timeout expiration value * @param unit expiration unit - * @return true if expiration was set, false otherwise + * @return true if expiration was set, false otherwise. {@literal null} when used in pipeline / transaction. */ + @Nullable Boolean expire(long timeout, TimeUnit unit); /** * Sets the key time-to-live/expiration. - * + * * @param date expiration date - * @return true if expiration was set, false otherwise + * @return true if expiration was set, false otherwise. {@literal null} when used in pipeline / transaction. */ + @Nullable Boolean expireAt(Date date); /** * Removes the expiration (if any) of the key. - * - * @return true if expiration was removed, false otherwise + * + * @return true if expiration was removed, false otherwise. {@literal null} when used in pipeline / transaction. */ + @Nullable Boolean persist(); /** * Renames the key.
* Note: The new name for empty collections will be propagated on add of first element. - * - * @param newKey new key + * + * @param newKey new key. Must not be {@literal null}. */ void rename(K newKey); } diff --git a/src/main/java/org/springframework/data/redis/core/BoundListOperations.java b/src/main/java/org/springframework/data/redis/core/BoundListOperations.java index 7347bd391..86402ee9a 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundListOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundListOperations.java @@ -18,6 +18,8 @@ package org.springframework.data.redis.core; import java.util.List; import java.util.concurrent.TimeUnit; +import org.springframework.lang.Nullable; + /** * List operations bound to a certain key. * @@ -31,9 +33,10 @@ public interface BoundListOperations extends BoundKeyOperations { * * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LRANGE */ + @Nullable List range(long start, long end); /** @@ -48,81 +51,90 @@ public interface BoundListOperations extends BoundKeyOperations { /** * Get the size of list stored at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LLEN */ + @Nullable Long size(); /** * Prepend {@code value} to the bound key. * * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSH */ + @Nullable Long leftPush(V value); /** * Prepend {@code values} to the bound key. * * @param values - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSH */ + @Nullable Long leftPushAll(V... values); /** * Prepend {@code values} to the bound key only if the list exists. * * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSHX */ + @Nullable Long leftPushIfPresent(V value); /** * Prepend {@code values} to the bound key before {@code value}. * * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPUSH */ + @Nullable Long leftPush(V pivot, V value); /** * Append {@code value} to the bound key. * * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSH */ + @Nullable Long rightPush(V value); /** * Append {@code values} to the bound key. * * @param values - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSH */ + @Nullable Long rightPushAll(V... values); /** * Append {@code values} to the bound key only if the list exists. * * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSHX */ + @Nullable Long rightPushIfPresent(V value); /** * Append {@code values} to the bound key before {@code value}. * * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPUSH */ + @Nullable Long rightPush(V pivot, V value); /** @@ -139,26 +151,29 @@ public interface BoundListOperations extends BoundKeyOperations { * * @param count * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LREM */ + @Nullable Long remove(long count, Object value); /** * Get element at {@code index} form list at the bound key. * * @param index - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LINDEX */ + @Nullable V index(long index); /** * Removes and returns first element in list stored at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: LPOP */ + @Nullable V leftPop(); /** @@ -167,17 +182,19 @@ public interface BoundListOperations extends BoundKeyOperations { * * @param timeout * @param unit must not be {@literal null}. - * @return + * @return {@literal null} when timeout reached or used in pipeline / transaction. * @see Redis Documentation: BLPOP */ + @Nullable V leftPop(long timeout, TimeUnit unit); /** * Removes and returns last element in list stored at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RPOP */ + @Nullable V rightPop(); /** @@ -186,9 +203,10 @@ public interface BoundListOperations extends BoundKeyOperations { * * @param timeout * @param unit must not be {@literal null}. - * @return + * @return {@literal null} when timeout reached or used in pipeline / transaction. * @see Redis Documentation: BRPOP */ + @Nullable V rightPop(long timeout, TimeUnit unit); RedisOperations getOperations(); diff --git a/src/main/java/org/springframework/data/redis/core/BoundSetOperations.java b/src/main/java/org/springframework/data/redis/core/BoundSetOperations.java index 6dd2526a3..84788fb4b 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundSetOperations.java @@ -19,9 +19,11 @@ import java.util.Collection; import java.util.List; import java.util.Set; +import org.springframework.lang.Nullable; + /** * Set operations bound to a certain key. - * + * * @author Costin Leau * @author Mark Paluch */ @@ -31,26 +33,29 @@ public interface BoundSetOperations extends BoundKeyOperations { * Add given {@code values} to set at the bound key. * * @param values - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SADD */ + @Nullable Long add(V... values); /** * Remove given {@code values} from set at the bound key and return the number of removed elements. * * @param values - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SREM */ + @Nullable Long remove(Object... values); /** * Remove and return a random member from set at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SPOP */ + @Nullable V pop(); /** @@ -58,44 +63,49 @@ public interface BoundSetOperations extends BoundKeyOperations { * * @param destKey must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SMOVE */ + @Nullable Boolean move(K destKey, V value); /** * Get size of set at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SCARD */ + @Nullable Long size(); /** * Check if set at the bound key contains {@code value}. * * @param o - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SISMEMBER */ + @Nullable Boolean isMember(Object o); /** * Returns the members intersecting all given sets at the bound key and {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SINTER */ + @Nullable Set intersect(K key); /** * Returns the members intersecting all given sets at the bound key and {@code keys}. * * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SINTER */ + @Nullable Set intersect(Collection keys); /** @@ -103,7 +113,6 @@ public interface BoundSetOperations extends BoundKeyOperations { * * @param key must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: SINTERSTORE */ void intersectAndStore(K key, K destKey); @@ -113,7 +122,6 @@ public interface BoundSetOperations extends BoundKeyOperations { * * @param keys must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: SINTERSTORE */ void intersectAndStore(Collection keys, K destKey); @@ -122,18 +130,20 @@ public interface BoundSetOperations extends BoundKeyOperations { * Union all sets at given {@code key} and {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SUNION */ + @Nullable Set union(K key); /** * Union all sets at given {@code keys} and {@code keys}. * * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SUNION */ + @Nullable Set union(Collection keys); /** @@ -141,7 +151,6 @@ public interface BoundSetOperations extends BoundKeyOperations { * * @param key must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: SUNIONSTORE */ void unionAndStore(K key, K destKey); @@ -151,7 +160,6 @@ public interface BoundSetOperations extends BoundKeyOperations { * * @param keys must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: SUNIONSTORE */ void unionAndStore(Collection keys, K destKey); @@ -160,18 +168,20 @@ public interface BoundSetOperations extends BoundKeyOperations { * Diff all sets for given the bound key and {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SDIFF */ + @Nullable Set diff(K key); /** * Diff all sets for given the bound key and {@code keys}. * * @param keys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SDIFF */ + @Nullable Set diff(Collection keys); /** @@ -179,7 +189,6 @@ public interface BoundSetOperations extends BoundKeyOperations { * * @param keys must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: SDIFFSTORE */ void diffAndStore(K keys, K destKey); @@ -189,7 +198,6 @@ public interface BoundSetOperations extends BoundKeyOperations { * * @param keys must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: SDIFFSTORE */ void diffAndStore(Collection keys, K destKey); @@ -197,44 +205,52 @@ public interface BoundSetOperations extends BoundKeyOperations { /** * Get all elements of set at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SMEMBERS */ + @Nullable Set members(); /** * Get random element from set at the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SRANDMEMBER */ + @Nullable V randomMember(); /** * Get {@code count} distinct random elements from set at the bound key. * * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SRANDMEMBER */ + @Nullable Set distinctRandomMembers(long count); /** * Get {@code count} random elements from set at the bound key. * * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SRANDMEMBER */ + @Nullable List randomMembers(long count); /** * @param options - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.4 */ + @Nullable Cursor scan(ScanOptions options); - + + /** + * @return never {@literal null}. + */ RedisOperations getOperations(); } 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 8b3381d91..031472071 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundValueOperations.java @@ -17,6 +17,8 @@ package org.springframework.data.redis.core; import java.util.concurrent.TimeUnit; +import org.springframework.lang.Nullable; + /** * Value (or String in Redis terminology) operations bound to a certain key. * @@ -28,7 +30,7 @@ public interface BoundValueOperations extends BoundKeyOperations { /** * Set {@code value} for the bound key. * - * @param value + * @param value must not be {@literal null}. * @see Redis Documentation: SET */ void set(V value); @@ -36,7 +38,7 @@ public interface BoundValueOperations extends BoundKeyOperations { /** * Set the {@code value} and expiration {@code timeout} for the bound key. * - * @param value + * @param value must not be {@literal null}. * @param timeout * @param unit must not be {@literal null}. * @see Redis Documentation: SETEX @@ -46,47 +48,59 @@ public interface BoundValueOperations extends BoundKeyOperations { /** * Set the bound key to hold the string {@code value} if the bound key is absent. * - * @param value + * @param value must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SETNX */ + @Nullable Boolean setIfAbsent(V value); /** * Get the value of the bound key. * + * @return {@literal null} when used in pipeline / transaction.ø * @see Redis Documentation: GET */ + @Nullable V get(); /** * Set {@code value} of the bound key and return its old value. * + * @return {@literal null} when used in pipeline / transaction.ø * @see Redis Documentation: GETSET */ + @Nullable V getAndSet(V value); /** * Increment an integer value stored as string value under the bound key by {@code delta}. * * @param delta + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: INCR */ + @Nullable Long increment(long delta); /** * Increment a floating point number value stored as string value under the bound key by {@code delta}. * * @param delta + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: INCRBYFLOAT */ + @Nullable Double increment(double delta); /** * Append a {@code value} to the bound key. * - * @param value + * @param value must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: APPEND */ + @Nullable Integer append(String value); /** @@ -96,12 +110,13 @@ public interface BoundValueOperations extends BoundKeyOperations { * @param end * @see Redis Documentation: GETRANGE */ + @Nullable String get(long start, long end); /** * Overwrite parts of the bound key starting at the specified {@code offset} with given {@code value}. * - * @param value + * @param value must not be {@literal null}. * @param offset * @see Redis Documentation: SETRANGE */ @@ -110,9 +125,14 @@ public interface BoundValueOperations extends BoundKeyOperations { /** * Get the length of the value stored at the bound key. * + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: STRLEN */ + @Nullable Long size(); + /** + * @return never {@literal null}. + */ RedisOperations getOperations(); } diff --git a/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java b/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java index 7027cabb8..64b8df62f 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java @@ -22,6 +22,7 @@ import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; +import org.springframework.lang.Nullable; /** * ZSet (or SortedSet) operations bound to a certain key. @@ -37,27 +38,30 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param score the score. * @param value the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZADD */ + @Nullable Boolean add(V value, double score); /** * Add {@code tuples} to a sorted set at the bound key, or update its {@code score} if it already exists. * * @param tuples must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZADD */ + @Nullable Long add(Set> tuples); /** * Remove {@code values} from sorted set. Return number of removed elements. * * @param values must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREM */ + @Nullable Long remove(Object... values); /** @@ -65,27 +69,30 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param delta * @param value the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZINCRBY */ + @Nullable Double incrementScore(V value, double delta); /** * Determine the index of element with {@code value} in a sorted set. * * @param o the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANK */ + @Nullable Long rank(Object o); /** * Determine the index of element with {@code value} in a sorted set when scored high to low. * * @param o the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANK */ + @Nullable Long reverseRank(Object o); /** @@ -93,9 +100,10 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGE */ + @Nullable Set range(long start, long end); /** @@ -103,9 +111,10 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGE */ + @Nullable Set> rangeWithScores(long start, long end); /** @@ -113,9 +122,10 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable Set rangeByScore(double min, double max); /** @@ -123,9 +133,10 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable Set> rangeByScoreWithScores(double min, double max); /** @@ -133,9 +144,10 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGE */ + @Nullable Set reverseRange(long start, long end); /** @@ -143,9 +155,10 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGE */ + @Nullable Set> reverseRangeWithScores(long start, long end); /** @@ -153,9 +166,10 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGE */ + @Nullable Set reverseRangeByScore(double min, double max); /** @@ -164,9 +178,10 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable Set> reverseRangeByScoreWithScores(double min, double max); /** @@ -174,36 +189,40 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZCOUNT */ + @Nullable Long count(double min, double max); /** * Returns the number of elements of the sorted set stored with given the bound key. * * @see #zCard() - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZCARD */ + @Nullable Long size(); /** * Get the size of sorted set with the bound key. * - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.3 * @see Redis Documentation: ZCARD */ + @Nullable Long zCard(); /** * Get the score of element with {@code value} from sorted set with key the bound key. * * @param o the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZSCORE */ + @Nullable Double score(Object o); /** @@ -211,7 +230,6 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param start * @param end - * @return * @see Redis Documentation: ZREMRANGEBYRANK */ void removeRange(long start, long end); @@ -221,7 +239,6 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param min * @param max - * @return * @see Redis Documentation: ZREMRANGEBYSCORE */ void removeRangeByScore(double min, double max); @@ -231,7 +248,6 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param otherKey must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: ZUNIONSTORE */ void unionAndStore(K otherKey, K destKey); @@ -241,7 +257,6 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param otherKeys must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: ZUNIONSTORE */ void unionAndStore(Collection otherKeys, K destKey); @@ -251,7 +266,6 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param otherKey must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: ZINTERSTORE */ void intersectAndStore(K otherKey, K destKey); @@ -261,7 +275,6 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param otherKeys must not be {@literal null}. * @param destKey must not be {@literal null}. - * @return * @see Redis Documentation: ZINTERSTORE */ void intersectAndStore(Collection otherKeys, K destKey); @@ -281,9 +294,11 @@ public interface BoundZSetOperations extends BoundKeyOperations { * {@link Range#getMax()}. * * @param range must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @since 1.7 * @see Redis Documentation: ZRANGEBYLEX */ + @Nullable Set rangeByLex(Range range); /** @@ -293,11 +308,15 @@ public interface BoundZSetOperations extends BoundKeyOperations { * * @param range must not be {@literal null}. * @param limit can be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.7 * @see Redis Documentation: ZRANGEBYLEX */ + @Nullable Set rangeByLex(Range range, Limit limit); + /** + * @return never {@literal null}. + */ RedisOperations getOperations(); } diff --git a/src/main/java/org/springframework/data/redis/core/CloseSuppressingInvocationHandler.java b/src/main/java/org/springframework/data/redis/core/CloseSuppressingInvocationHandler.java index 149659364..c151a7500 100644 --- a/src/main/java/org/springframework/data/redis/core/CloseSuppressingInvocationHandler.java +++ b/src/main/java/org/springframework/data/redis/core/CloseSuppressingInvocationHandler.java @@ -1,5 +1,5 @@ /* - * 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. @@ -20,12 +20,14 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.lang.Nullable; /** * Invocation handler that suppresses close calls on {@link RedisConnection}. * * @see RedisConnection#close() * @author Costin Leau + * @author Christoph Strobl */ class CloseSuppressingInvocationHandler implements InvocationHandler { @@ -39,6 +41,8 @@ class CloseSuppressingInvocationHandler implements InvocationHandler { this.target = target; } + @Override + @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals(EQUALS)) { diff --git a/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java b/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java index a2a8994ba..398fc45f0 100644 --- a/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java +++ b/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java @@ -18,6 +18,7 @@ package org.springframework.data.redis.core; import java.io.IOException; import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -61,6 +62,7 @@ public class ConvertingCursor implements Cursor { * @see java.util.Iterator#next() */ @Override + @Nullable public T next() { return converter.convert(delegate.next()); } diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundKeyOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundKeyOperations.java index 322f07fed..9b8dfaef3 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundKeyOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundKeyOperations.java @@ -22,6 +22,7 @@ import java.util.concurrent.TimeUnit; * Default {@link BoundKeyOperations} implementation. Meant for internal usage. * * @author Costin Leau + * @author Christoph Strobl */ abstract class DefaultBoundKeyOperations implements BoundKeyOperations { @@ -30,7 +31,7 @@ abstract class DefaultBoundKeyOperations implements BoundKeyOperations { DefaultBoundKeyOperations(K key, RedisOperations operations) { - setKey(key); + this.key = key; this.ops = operations; } @@ -43,10 +44,6 @@ abstract class DefaultBoundKeyOperations implements BoundKeyOperations { return key; } - protected void setKey(K key) { - this.key = key; - } - /* * (non-Javadoc) * @see org.springframework.data.redis.core.BoundKeyOperations#expire(long, java.util.concurrent.TimeUnit) diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java index 8db6cdd0c..660903214 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundZSetOperations.java @@ -170,7 +170,7 @@ class DefaultBoundZSetOperations extends DefaultBoundKeyOperations impl */ @Override public Set rangeByLex(Range range) { - return rangeByLex(range, null); + return rangeByLex(range, Limit.unlimited()); } /* diff --git a/src/main/java/org/springframework/data/redis/core/DefaultClusterOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultClusterOperations.java index 5b76000c4..cce15f9b6 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultClusterOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultClusterOperations.java @@ -24,6 +24,7 @@ import org.springframework.data.redis.connection.RedisClusterConnection; import org.springframework.data.redis.connection.RedisClusterNode; import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; import org.springframework.data.redis.connection.RedisServerCommands.MigrateOption; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -257,9 +258,10 @@ class DefaultClusterOperations extends AbstractOperations implements /** * Executed wrapped command upon {@link RedisClusterConnection}. * - * @param callback - * @return + * @param callback must not be {@literal null}. + * @return execution result. Can be {@literal null}. */ + @Nullable public T execute(RedisClusterCallback callback) { Assert.notNull(callback, "ClusterCallback must not be null!"); diff --git a/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java index 6f43705c5..3dd849fe6 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java @@ -51,7 +51,7 @@ class DefaultHashOperations extends AbstractOperations imp byte[] rawHashKey = rawHashKey(hashKey); byte[] rawHashValue = execute(connection -> connection.hGet(rawKey, rawHashKey), true); - return (HV) deserializeHashValue(rawHashValue); + return (HV) rawHashValue != null ? deserializeHashValue(rawHashValue) : null; } /* @@ -100,7 +100,7 @@ class DefaultHashOperations extends AbstractOperations imp byte[] rawKey = rawKey(key); Set rawValues = execute(connection -> connection.hKeys(rawKey), true); - return deserializeHashKeys(rawValues); + return rawValues != null ? deserializeHashKeys(rawValues) : Collections.emptySet(); } /* @@ -204,7 +204,7 @@ class DefaultHashOperations extends AbstractOperations imp byte[] rawKey = rawKey(key); List rawValues = execute(connection -> connection.hVals(rawKey), true); - return deserializeHashValues(rawValues); + return rawValues != null ? deserializeHashValues(rawValues) : Collections.emptyList(); } /* @@ -230,7 +230,7 @@ class DefaultHashOperations extends AbstractOperations imp byte[] rawKey = rawKey(key); Map entries = execute(connection -> connection.hGetAll(rawKey), true); - return deserializeHashMap(entries); + return entries != null ? deserializeHashMap(entries) : Collections.emptyMap(); } /* diff --git a/src/main/java/org/springframework/data/redis/core/DefaultTypedTuple.java b/src/main/java/org/springframework/data/redis/core/DefaultTypedTuple.java index 2f61c9055..b2e79013a 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultTypedTuple.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultTypedTuple.java @@ -18,6 +18,7 @@ package org.springframework.data.redis.core; import java.util.Arrays; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; +import org.springframework.lang.Nullable; /** * Default implementation of TypedTuple. @@ -26,24 +27,26 @@ import org.springframework.data.redis.core.ZSetOperations.TypedTuple; */ public class DefaultTypedTuple implements TypedTuple { - private final Double score; - private final V value; + private final @Nullable Double score; + private final @Nullable V value; /** * Constructs a new DefaultTypedTuple instance. * - * @param value - * @param score + * @param value can be {@literal null}. + * @param score can be {@literal null}. */ - public DefaultTypedTuple(V value, Double score) { + public DefaultTypedTuple(@Nullable V value, @Nullable Double score) { this.score = score; this.value = value; } + @Nullable public Double getScore() { return score; } + @Nullable public V getValue() { return value; } diff --git a/src/main/java/org/springframework/data/redis/core/GeoOperations.java b/src/main/java/org/springframework/data/redis/core/GeoOperations.java index 321b1bb24..202e5381a 100644 --- a/src/main/java/org/springframework/data/redis/core/GeoOperations.java +++ b/src/main/java/org/springframework/data/redis/core/GeoOperations.java @@ -25,6 +25,7 @@ import org.springframework.data.geo.Metric; import org.springframework.data.geo.Point; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs; +import org.springframework.lang.Nullable; /** * Redis operations for geo commands. @@ -43,10 +44,11 @@ public interface GeoOperations { * @param key must not be {@literal null}. * @param point must not be {@literal null}. * @param member must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOADD */ + @Nullable Long add(K key, Point point, M member); /** @@ -55,11 +57,12 @@ public interface GeoOperations { * @param key must not be {@literal null}. * @param point must not be {@literal null}. * @param member must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD * @deprecated since 2.0, use {@link #add(Object, Point, Object)}. */ @Deprecated + @Nullable default Long geoAdd(K key, Point point, M member) { return add(key, point, member); } @@ -69,10 +72,11 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param location must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOADD */ + @Nullable Long add(K key, GeoLocation location); /** @@ -80,11 +84,12 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param location must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD * @deprecated since 2.0, use {@link #add(Object, GeoLocation)}. */ @Deprecated + @Nullable default Long geoAdd(K key, GeoLocation location) { return add(key, location); } @@ -94,10 +99,11 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param memberCoordinateMap must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOADD */ + @Nullable Long add(K key, Map memberCoordinateMap); /** @@ -105,11 +111,12 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param memberCoordinateMap must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD * @deprecated since 2.0, use {@link #add(Object, Map)}. */ @Deprecated + @Nullable default Long geoAdd(K key, Map memberCoordinateMap) { return add(key, memberCoordinateMap); } @@ -119,10 +126,11 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param locations must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOADD */ + @Nullable Long add(K key, Iterable> locations); /** @@ -130,11 +138,12 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param locations must not be {@literal null}. - * @return Number of elements added. + * @return Number of elements added. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: GEOADD * @deprecated since 2.0, use {@link #add(Object, Iterable)}. */ @Deprecated + @Nullable default Long geoAdd(K key, Iterable> locations) { return add(key, locations); } @@ -149,6 +158,7 @@ public interface GeoOperations { * @since 2.0 * @see Redis Documentation: GEODIST */ + @Nullable Distance distance(K key, M member1, M member2); /** @@ -162,6 +172,7 @@ public interface GeoOperations { * @deprecated since 2.0, use {@link #distance(Object, Object, Object)}. */ @Deprecated + @Nullable default Distance geoDist(K key, M member1, M member2) { return distance(key, member1, member2); } @@ -177,6 +188,7 @@ public interface GeoOperations { * @since 2.0 * @see Redis Documentation: GEODIST */ + @Nullable Distance distance(K key, M member1, M member2, Metric metric); /** @@ -191,6 +203,7 @@ public interface GeoOperations { * @deprecated since 2.0, use {@link #distance(Object, Object, Object, Metric)}. */ @Deprecated + @Nullable default Distance geoDist(K key, M member1, M member2, Metric metric) { return distance(key, member1, member2, metric); } @@ -200,10 +213,11 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOHASH */ + @Nullable List hash(K key, M... members); /** @@ -211,11 +225,12 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEOHASH * @deprecated since 2.0, use {@link #hash(Object, Object[])}. */ @Deprecated + @Nullable default List geoHash(K key, M... members) { return hash(key, members); } @@ -225,10 +240,11 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEOPOS */ + @Nullable List position(K key, M... members); /** @@ -236,11 +252,12 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param members must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEOPOS * @deprecated since 2.0, use {@link #position(Object, Object[])}. */ @Deprecated + @Nullable default List geoPos(K key, M... members) { return position(key, members); } @@ -250,10 +267,11 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param within must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUS */ + @Nullable GeoResults> radius(K key, Circle within); /** @@ -261,11 +279,12 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param within must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUS * @deprecated since 2.0, use {@link #radius(Object, Circle)}. */ @Deprecated + @Nullable default GeoResults> geoRadius(K key, Circle within) { return radius(key, within); } @@ -276,10 +295,11 @@ public interface GeoOperations { * @param key must not be {@literal null}. * @param within must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUS */ + @Nullable GeoResults> radius(K key, Circle within, GeoRadiusCommandArgs args); /** @@ -288,11 +308,12 @@ public interface GeoOperations { * @param key must not be {@literal null}. * @param within must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUS * @deprecated since 2.0, use {@link #radius(Object, Circle, GeoRadiusCommandArgs)}. */ @Deprecated + @Nullable default GeoResults> geoRadius(K key, Circle within, GeoRadiusCommandArgs args) { return radius(key, within, args); } @@ -304,10 +325,11 @@ public interface GeoOperations { * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @param radius - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUSBYMEMBER */ + @Nullable GeoResults> radius(K key, M member, double radius); /** @@ -317,11 +339,12 @@ public interface GeoOperations { * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @param radius - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUSBYMEMBER * @deprecated since 2.0, use {@link #radius(Object, Object, double)}. */ @Deprecated + @Nullable default GeoResults> geoRadiusByMember(K key, M member, double radius) { return radius(key, member, radius); } @@ -333,10 +356,11 @@ public interface GeoOperations { * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @param distance must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUSBYMEMBER */ + @Nullable GeoResults> radius(K key, M member, Distance distance); /** @@ -346,11 +370,12 @@ public interface GeoOperations { * @param key must not be {@literal null}. * @param member must not be {@literal null}. * @param distance must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUSBYMEMBER * @deprecated since 2.0, use {@link #radius(Object, Object, Distance)}. */ @Deprecated + @Nullable default GeoResults> geoRadiusByMember(K key, M member, Distance distance) { return radius(key, member, distance); } @@ -363,10 +388,11 @@ public interface GeoOperations { * @param member must not be {@literal null}. * @param distance must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @since 2.0 * @see Redis Documentation: GEORADIUSBYMEMBER */ + @Nullable GeoResults> radius(K key, M member, Distance distance, GeoRadiusCommandArgs args); /** @@ -377,11 +403,12 @@ public interface GeoOperations { * @param member must not be {@literal null}. * @param distance must not be {@literal null}. * @param args must not be {@literal null}. - * @return never {@literal null}. + * @return never {@literal null} unless used in pipeline / transaction. * @see Redis Documentation: GEORADIUSBYMEMBER * @deprecated since 2.0, use {@link #radius(Object, Object, Distance, GeoRadiusCommandArgs)}. */ @Deprecated + @Nullable default GeoResults> geoRadiusByMember(K key, M member, Distance distance, GeoRadiusCommandArgs args) { return radius(key, member, distance, args); } @@ -391,9 +418,10 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param members must not be {@literal null}. - * @return Number of elements removed. + * @return Number of elements removed. {@literal null} when used in pipeline / transaction. * @since 2.0 */ + @Nullable Long remove(K key, M... members); /** @@ -401,10 +429,11 @@ public interface GeoOperations { * * @param key must not be {@literal null}. * @param members must not be {@literal null}. - * @return Number of elements removed. + * @return Number of elements removed. {@literal null} when used in pipeline / transaction. * @deprecated since 2.0, use {@link #remove(Object, Object[])}. */ @Deprecated + @Nullable default Long geoRemove(K key, M... members) { return remove(key, members); } diff --git a/src/main/java/org/springframework/data/redis/core/HashOperations.java b/src/main/java/org/springframework/data/redis/core/HashOperations.java index 911f956a5..e278e2d47 100644 --- a/src/main/java/org/springframework/data/redis/core/HashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/HashOperations.java @@ -20,6 +20,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.springframework.lang.Nullable; + /** * Redis map specific operations working on a hash. * @@ -34,7 +36,7 @@ public interface HashOperations { * * @param key must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ Long delete(H key, Object... hashKeys); @@ -43,7 +45,7 @@ public interface HashOperations { * * @param key must not be {@literal null}. * @param hashKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ Boolean hasKey(H key, Object hashKey); @@ -52,8 +54,9 @@ public interface HashOperations { * * @param key must not be {@literal null}. * @param hashKey must not be {@literal null}. - * @return + * @return {@literal null} when key or hashKey does not exist or used in pipeline / transaction. */ + @Nullable HV get(H key, Object hashKey); /** @@ -61,7 +64,7 @@ public interface HashOperations { * * @param key must not be {@literal null}. * @param hashKeys must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ List multiGet(H key, Collection hashKeys); @@ -71,7 +74,7 @@ public interface HashOperations { * @param key must not be {@literal null}. * @param hashKey must not be {@literal null}. * @param delta - * @return + * @return {@literal null} when used in pipeline / transaction. */ Long increment(H key, HK hashKey, long delta); @@ -81,7 +84,7 @@ public interface HashOperations { * @param key must not be {@literal null}. * @param hashKey must not be {@literal null}. * @param delta - * @return + * @return {@literal null} when used in pipeline / transaction. */ Double increment(H key, HK hashKey, double delta); @@ -89,7 +92,7 @@ public interface HashOperations { * Get key set (fields) of hash at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ Set keys(H key); @@ -97,7 +100,7 @@ public interface HashOperations { * Get size of hash at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ Long size(H key); @@ -124,7 +127,7 @@ public interface HashOperations { * @param key must not be {@literal null}. * @param hashKey must not be {@literal null}. * @param value - * @return + * @return {@literal null} when used in pipeline / transaction. */ Boolean putIfAbsent(H key, HK hashKey, HV value); @@ -132,7 +135,7 @@ public interface HashOperations { * Get entry set (values) of hash at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ List values(H key); @@ -140,7 +143,7 @@ public interface HashOperations { * Get entire hash stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ Map entries(H key); @@ -150,13 +153,13 @@ public interface HashOperations { * * @param key must not be {@literal null}. * @param options - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.4 */ Cursor> scan(H key, ScanOptions options); /** - * @return + * @return never {@literal null}. */ RedisOperations getOperations(); } 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 84d6fc7f8..a8ab8a716 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisAccessor.java +++ b/src/main/java/org/springframework/data/redis/core/RedisAccessor.java @@ -19,6 +19,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -31,17 +32,18 @@ public class RedisAccessor implements InitializingBean { /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); - private RedisConnectionFactory connectionFactory; + private @Nullable RedisConnectionFactory connectionFactory; public void afterPropertiesSet() { - Assert.notNull(getConnectionFactory(), "RedisConnectionFactory is required"); + Assert.state(getConnectionFactory() != null, "RedisConnectionFactory is required"); } /** * Returns the connectionFactory. * - * @return Returns the connectionFactory + * @return Returns the connectionFactory. Can be {@literal null} */ + @Nullable public RedisConnectionFactory getConnectionFactory() { return connectionFactory; } 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 7502ebc30..29875d1b5 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java +++ b/src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java @@ -60,6 +60,7 @@ import org.springframework.data.redis.listener.KeyExpirationEventMessageListener import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.util.ByteUtils; import org.springframework.data.util.CloseableIterator; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -103,13 +104,12 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter private RedisOperations redisOps; private RedisConverter converter; - private RedisMessageListenerContainer messageListenerContainer; - private final AtomicReference expirationListener = new AtomicReference<>( - null); - private ApplicationEventPublisher eventPublisher; + private @Nullable RedisMessageListenerContainer messageListenerContainer; + private final AtomicReference expirationListener = new AtomicReference<>(null); + private @Nullable ApplicationEventPublisher eventPublisher; private EnableKeyspaceEvents enableKeyspaceEvents = EnableKeyspaceEvents.OFF; - private String keyspaceNotificationsConfigParameter = null; + private @Nullable String keyspaceNotificationsConfigParameter = null; /** * Creates new {@link RedisKeyValueAdapter} with default {@link RedisMappingContext} and default @@ -751,7 +751,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter * @see org.springframework.data.redis.listener.KeyspaceEventMessageListener#onMessage(org.springframework.data.redis.connection.Message, byte[]) */ @Override - public void onMessage(Message message, byte[] pattern) { + public void onMessage(Message message, @Nullable byte[] pattern) { if (!isKeyExpirationMessage(message)) { return; @@ -775,8 +775,7 @@ public class RedisKeyValueAdapter extends AbstractKeyValueAdapter Object value = converter.read(Object.class, new RedisData(hash)); String channel = !ObjectUtils.isEmpty(message.getChannel()) - ? converter.getConversionService().convert(message.getChannel(), String.class) - : null; + ? converter.getConversionService().convert(message.getChannel(), String.class) : null; RedisKeyExpiredEvent event = new RedisKeyExpiredEvent(channel, key, value); 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 df88d966c..9c43880ef 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisOperations.java +++ b/src/main/java/org/springframework/data/redis/core/RedisOperations.java @@ -28,6 +28,7 @@ import org.springframework.data.redis.core.query.SortQuery; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.data.redis.core.types.RedisClientInfo; import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.lang.Nullable; /** * Interface that specified a basic set of Redis operations, implemented by {@link RedisTemplate}. Not often used but a @@ -50,9 +51,10 @@ public interface RedisOperations { * the template do its work. * * @param return type - * @param action callback object that specifies the Redis action + * @param action callback object that specifies the Redis action. Must not be {@literal null}. * @return a result object returned by the action or null */ + @Nullable T execute(RedisCallback action); /** @@ -60,9 +62,10 @@ public interface RedisOperations { * capabilities through {@link #multi()} and {@link #watch(Collection)} operations. * * @param return type - * @param session session callback + * @param session session callback. Must not be {@literal null}. * @return result object returned by the action or null */ + @Nullable T execute(SessionCallback session); /** @@ -115,6 +118,7 @@ public interface RedisOperations { * @return The return value of the script or null if {@link RedisScript#getResultType()} is null, likely indicating a * throw-away status reply (i.e. "OK") */ + @Nullable T execute(RedisScript script, List keys, Object... args); /** @@ -129,6 +133,7 @@ public interface RedisOperations { * @return The return value of the script or null if {@link RedisScript#getResultType()} is null, likely indicating a * throw-away status reply (i.e. "OK") */ + @Nullable T execute(RedisScript script, RedisSerializer argsSerializer, RedisSerializer resultSerializer, List keys, Object... args); @@ -140,6 +145,7 @@ public interface RedisOperations { * @return * @since 1.8 */ + @Nullable T executeWithStickyConnection(RedisCallback callback); // ------------------------------------------------------------------------- @@ -162,41 +168,46 @@ public interface RedisOperations { * @return {@literal true} if the key was removed. * @see Redis Documentation: DEL */ + @Nullable Boolean delete(K key); /** * Delete given {@code keys}. * * @param keys must not be {@literal null}. - * @return The number of keys that were removed. + * @return The number of keys that were removed. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: DEL */ + @Nullable Long delete(Collection keys); /** * Determine the type stored at {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: TYPE */ + @Nullable DataType type(K key); /** * Find all keys matching the given {@code pattern}. * * @param pattern must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: KEYS */ + @Nullable Set keys(K pattern); /** * Return a random key from the keyspace. * - * @return + * @return {@literal null} no keys exist or when used in pipeline / transaction. * @see Redis Documentation: RANDOMKEY */ + @Nullable K randomKey(); /** @@ -213,9 +224,10 @@ public interface RedisOperations { * * @param oldKey must not be {@literal null}. * @param newKey must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: RENAMENX */ + @Nullable Boolean renameIfAbsent(K oldKey, K newKey); /** @@ -224,8 +236,9 @@ public interface RedisOperations { * @param key must not be {@literal null}. * @param timeout * @param unit must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Boolean expire(K key, long timeout, TimeUnit unit); /** @@ -233,17 +246,19 @@ public interface RedisOperations { * * @param key must not be {@literal null}. * @param date must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. */ + @Nullable Boolean expireAt(K key, Date date); /** * Remove the expiration from given {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: PERSIST */ + @Nullable Boolean persist(K key); /** @@ -251,18 +266,20 @@ public interface RedisOperations { * * @param key must not be {@literal null}. * @param dbIndex - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: MOVE */ + @Nullable Boolean move(K key, int dbIndex); /** * Retrieve serialized version 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: DUMP */ + @Nullable byte[] dump(K key); /** @@ -280,9 +297,10 @@ public interface RedisOperations { * Get the time to live for {@code key} in seconds. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: TTL */ + @Nullable Long getExpire(K key); /** @@ -290,45 +308,50 @@ public interface RedisOperations { * * @param key must not be {@literal null}. * @param timeUnit must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.8 */ + @Nullable Long getExpire(K key, TimeUnit timeUnit); /** * Sort the elements for {@code query}. * * @param query must not be {@literal null}. - * @return the results of sort. + * @return the results of sort. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SORT */ + @Nullable List sort(SortQuery query); /** * Sort the elements for {@code query} applying {@link RedisSerializer}. * * @param query must not be {@literal null}. - * @return the deserialized results of sort. + * @return the deserialized results of sort. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SORT */ + @Nullable List sort(SortQuery query, RedisSerializer resultSerializer); /** * Sort the elements for {@code query} applying {@link BulkMapper}. * * @param query must not be {@literal null}. - * @return the deserialized results of sort. + * @return the deserialized results of sort. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SORT */ + @Nullable List sort(SortQuery query, BulkMapper bulkMapper); /** * Sort the elements for {@code query} applying {@link BulkMapper} and {@link RedisSerializer}. * * @param query must not be {@literal null}. - * @return the deserialized results of sort. + * @return the deserialized results of sort. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SORT */ + @Nullable List sort(SortQuery query, BulkMapper bulkMapper, RedisSerializer resultSerializer); /** @@ -336,9 +359,10 @@ public interface RedisOperations { * * @param query must not be {@literal null}. * @param storeKey must not be {@literal null}. - * @return number of values. + * @return number of values. {@literal null} when used in pipeline / transaction. * @see Redis Documentation: SORT */ + @Nullable Long sort(SortQuery query, K storeKey); // ------------------------------------------------------------------------- @@ -414,6 +438,7 @@ public interface RedisOperations { * @return {@link List} of {@link RedisClientInfo} objects. * @since 1.3 */ + @Nullable List getClientList(); /** 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 191b5d933..6428c5592 100644 --- a/src/main/java/org/springframework/data/redis/core/RedisTemplate.java +++ b/src/main/java/org/springframework/data/redis/core/RedisTemplate.java @@ -49,6 +49,7 @@ import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationUtils; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.lang.Nullable; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -88,8 +89,8 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation private boolean exposeConnection = false; private boolean initialized = false; private boolean enableDefaultSerializer = true; - private RedisSerializer defaultSerializer; - private ClassLoader classLoader; + private @Nullable RedisSerializer defaultSerializer; + private @Nullable ClassLoader classLoader; @SuppressWarnings("rawtypes") private RedisSerializer keySerializer = null; @SuppressWarnings("rawtypes") private RedisSerializer valueSerializer = null; @@ -97,15 +98,15 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation @SuppressWarnings("rawtypes") private RedisSerializer hashValueSerializer = null; private RedisSerializer stringSerializer = new StringRedisSerializer(); - private ScriptExecutor scriptExecutor; + private @Nullable ScriptExecutor scriptExecutor; // cache singleton objects (where possible) - private ValueOperations valueOps; - private ListOperations listOps; - private SetOperations setOps; - private ZSetOperations zSetOps; - private GeoOperations geoOps; - private HyperLogLogOperations hllOps; + private @Nullable ValueOperations valueOps; + private @Nullable ListOperations listOps; + private @Nullable SetOperations setOps; + private @Nullable ZSetOperations zSetOps; + private @Nullable GeoOperations geoOps; + private @Nullable HyperLogLogOperations hllOps; /** * Constructs a new RedisTemplate instance. @@ -165,6 +166,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * @see org.springframework.data.redis.core.RedisOperations#execute(org.springframework.data.redis.core.RedisCallback) */ @Override + @Nullable public T execute(RedisCallback action) { return execute(action, isExposeConnection()); } @@ -177,6 +179,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * @param exposeConnection whether to enforce exposure of the native Redis Connection to callback code * @return object returned by the action */ + @Nullable public T execute(RedisCallback action, boolean exposeConnection) { return execute(action, exposeConnection, false); } @@ -191,6 +194,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * @param pipeline whether to pipeline or not the connection for the execution * @return object returned by the action */ + @Nullable public T execute(RedisCallback action, boolean exposeConnection, boolean pipeline) { Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it"); @@ -435,6 +439,7 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation * * @return template default serializer */ + @Nullable public RedisSerializer getDefaultSerializer() { return defaultSerializer; } @@ -684,7 +689,9 @@ public class RedisTemplate extends RedisAccessor implements RedisOperation } protected List execRaw() { - return execute(RedisTxCommands::exec); + + List raw = execute(RedisTxCommands::exec); + return raw == null ? Collections.emptyList() : raw; } /* diff --git a/src/main/java/org/springframework/data/redis/core/ScanOptions.java b/src/main/java/org/springframework/data/redis/core/ScanOptions.java index 83bc1a8ef..744b1bc7e 100644 --- a/src/main/java/org/springframework/data/redis/core/ScanOptions.java +++ b/src/main/java/org/springframework/data/redis/core/ScanOptions.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.core; +import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; /** @@ -28,8 +29,8 @@ public class ScanOptions { public static ScanOptions NONE = new ScanOptions(); - private Long count; - private String pattern; + private @Nullable Long count; + private @Nullable String pattern; private ScanOptions() {} @@ -42,10 +43,12 @@ public class ScanOptions { return new ScanOptionsBuilder(); } + @Nullable public Long getCount() { return count; } + @Nullable public String getPattern() { return pattern; } diff --git a/src/main/java/org/springframework/data/redis/core/ZSetOperations.java b/src/main/java/org/springframework/data/redis/core/ZSetOperations.java index 9634b2837..90c728e23 100644 --- a/src/main/java/org/springframework/data/redis/core/ZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ZSetOperations.java @@ -21,6 +21,7 @@ import java.util.Set; import org.springframework.data.redis.connection.RedisZSetCommands.Limit; import org.springframework.data.redis.connection.RedisZSetCommands.Range; import org.springframework.data.redis.connection.RedisZSetCommands.Tuple; +import org.springframework.lang.Nullable; /** * Redis ZSet/sorted set specific operations. @@ -36,8 +37,11 @@ public interface ZSetOperations { * Typed ZSet tuple. */ interface TypedTuple extends Comparable> { + + @Nullable V getValue(); + @Nullable Double getScore(); } @@ -47,9 +51,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param score the score. * @param value the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZADD */ + @Nullable Boolean add(K key, V value, double score); /** @@ -57,9 +62,10 @@ public interface ZSetOperations { * * @param key must not be {@literal null}. * @param tuples must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZADD */ + @Nullable Long add(K key, Set> tuples); /** @@ -67,9 +73,10 @@ public interface ZSetOperations { * * @param key must not be {@literal null}. * @param values must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREM */ + @Nullable Long remove(K key, Object... values); /** @@ -78,9 +85,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param delta * @param value the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZINCRBY */ + @Nullable Double incrementScore(K key, V value, double delta); /** @@ -88,9 +96,10 @@ public interface ZSetOperations { * * @param key must not be {@literal null}. * @param o the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANK */ + @Nullable Long rank(K key, Object o); /** @@ -98,9 +107,10 @@ public interface ZSetOperations { * * @param key must not be {@literal null}. * @param o the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANK */ + @Nullable Long reverseRank(K key, Object o); /** @@ -109,9 +119,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGE */ + @Nullable Set range(K key, long start, long end); /** @@ -120,9 +131,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGE */ + @Nullable Set> rangeWithScores(K key, long start, long end); /** @@ -131,9 +143,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable Set rangeByScore(K key, double min, double max); /** @@ -142,9 +155,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable Set> rangeByScoreWithScores(K key, double min, double max); /** @@ -156,9 +170,10 @@ public interface ZSetOperations { * @param max * @param offset * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable Set rangeByScore(K key, double min, double max, long offset, long count); /** @@ -170,9 +185,10 @@ public interface ZSetOperations { * @param max * @param offset * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZRANGEBYSCORE */ + @Nullable Set> rangeByScoreWithScores(K key, double min, double max, long offset, long count); /** @@ -181,9 +197,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGE */ + @Nullable Set reverseRange(K key, long start, long end); /** @@ -192,9 +209,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGE */ + @Nullable Set> reverseRangeWithScores(K key, long start, long end); /** @@ -203,9 +221,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGE */ + @Nullable Set reverseRangeByScore(K key, double min, double max); /** @@ -215,9 +234,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable Set> reverseRangeByScoreWithScores(K key, double min, double max); /** @@ -229,9 +249,10 @@ public interface ZSetOperations { * @param max * @param offset * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable Set reverseRangeByScore(K key, double min, double max, long offset, long count); /** @@ -243,9 +264,10 @@ public interface ZSetOperations { * @param max * @param offset * @param count - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREVRANGEBYSCORE */ + @Nullable Set> reverseRangeByScoreWithScores(K key, double min, double max, long offset, long count); /** @@ -254,9 +276,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZCOUNT */ + @Nullable Long count(K key, double min, double max); /** @@ -264,19 +287,21 @@ public interface ZSetOperations { * * @see #zCard(Object) * @param key - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZCARD */ + @Nullable Long size(K key); /** * Get the size of sorted set with {@code key}. * * @param key must not be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.3 * @see Redis Documentation: ZCARD */ + @Nullable Long zCard(K key); /** @@ -284,9 +309,10 @@ public interface ZSetOperations { * * @param key must not be {@literal null}. * @param o the value. - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZSCORE */ + @Nullable Double score(K key, Object o); /** @@ -295,9 +321,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param start * @param end - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREMRANGEBYRANK */ + @Nullable Long removeRange(K key, long start, long end); /** @@ -306,9 +333,10 @@ public interface ZSetOperations { * @param key must not be {@literal null}. * @param min * @param max - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZREMRANGEBYSCORE */ + @Nullable Long removeRangeByScore(K key, double min, double max); /** @@ -317,9 +345,10 @@ public interface ZSetOperations { * @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: ZUNIONSTORE */ + @Nullable Long unionAndStore(K key, K otherKey, K destKey); /** @@ -328,9 +357,10 @@ public interface ZSetOperations { * @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: ZUNIONSTORE */ + @Nullable Long unionAndStore(K key, Collection otherKeys, K destKey); /** @@ -339,9 +369,10 @@ public interface ZSetOperations { * @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: ZINTERSTORE */ + @Nullable Long intersectAndStore(K key, K otherKey, K destKey); /** @@ -350,9 +381,10 @@ public interface ZSetOperations { * @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: ZINTERSTORE */ + @Nullable Long intersectAndStore(K key, Collection otherKeys, K destKey); /** @@ -361,7 +393,7 @@ public interface ZSetOperations { * * @param key * @param options - * @return + * @return {@literal null} when used in pipeline / transaction. * @see Redis Documentation: ZSCAN * @since 1.4 */ @@ -373,9 +405,11 @@ public interface ZSetOperations { * * @param key must not be {@literal null}. * @param range must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. * @since 1.7 * @see Redis Documentation: ZRANGEBYLEX */ + @Nullable Set rangeByLex(K key, Range range); /** @@ -386,11 +420,15 @@ public interface ZSetOperations { * @param key must not be {@literal null} * @param range must not be {@literal null}. * @param limit can be {@literal null}. - * @return + * @return {@literal null} when used in pipeline / transaction. * @since 1.7 * @see Redis Documentation: ZRANGEBYLEX */ + @Nullable Set rangeByLex(K key, Range range, Limit limit); + /** + * @return never {@literal null}. + */ RedisOperations getOperations(); } 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 efc43ada3..44c2b3000 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 @@ -25,6 +25,7 @@ import org.springframework.core.convert.converter.ConverterFactory; import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; import org.springframework.util.NumberUtils; +import org.springframework.util.ObjectUtils; /** * Set of {@link ReadingConverter} and {@link WritingConverter} used to convert Objects into binary format. @@ -49,11 +50,6 @@ final class BinaryConverters { static class StringBasedConverter { byte[] fromString(String source) { - - if (source == null) { - return new byte[] {}; - } - return source.getBytes(CHARSET); } @@ -98,11 +94,6 @@ final class BinaryConverters { @Override public byte[] convert(Number source) { - - if (source == null) { - return new byte[] {}; - } - return fromString(source.toString()); } } @@ -117,11 +108,6 @@ final class BinaryConverters { @Override public byte[] convert(Enum source) { - - if (source == null) { - return new byte[] {}; - } - return fromString(source.name()); } } @@ -162,12 +148,11 @@ final class BinaryConverters { @Override public T convert(byte[] source) { - String value = toString(source); - - if (value == null || value.length() == 0) { + if (ObjectUtils.isEmpty(source)) { return null; } - return Enum.valueOf(this.enumType, value.trim()); + + return Enum.valueOf(this.enumType, toString(source).trim()); } } } @@ -196,7 +181,7 @@ final class BinaryConverters { @Override public T convert(byte[] source) { - if (source == null || source.length == 0) { + if (ObjectUtils.isEmpty(source)) { return null; } @@ -217,11 +202,6 @@ final class BinaryConverters { @Override public byte[] convert(Boolean source) { - - if (source == null) { - return new byte[] {}; - } - return source.booleanValue() ? _true : _false; } } @@ -236,7 +216,7 @@ final class BinaryConverters { @Override public Boolean convert(byte[] source) { - if (source == null || source.length == 0) { + if (ObjectUtils.isEmpty(source)) { return null; } @@ -254,11 +234,6 @@ final class BinaryConverters { @Override public byte[] convert(Date source) { - - if (source == null) { - return new byte[] {}; - } - return fromString(Long.toString(source.getTime())); } } @@ -273,7 +248,7 @@ final class BinaryConverters { @Override public Date convert(byte[] source) { - if (source == null || source.length == 0) { + if (ObjectUtils.isEmpty(source)) { return null; } 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 0d290ac68..171b696bd 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 @@ -26,6 +26,7 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -198,9 +199,6 @@ public class Bucket { public static Bucket newBucketFromRawMap(Map source) { Bucket bucket = new Bucket(); - if (source == null) { - return bucket; - } for (Map.Entry entry : source.entrySet()) { bucket.put(new String(entry.getKey(), CHARSET), entry.getValue()); @@ -217,13 +215,10 @@ public class Bucket { public static Bucket newBucketFromStringMap(Map source) { Bucket bucket = new Bucket(); - if (source == null) { - return bucket; - } for (Map.Entry entry : source.entrySet()) { - bucket.put(entry.getKey(), StringUtils.hasText(entry.getValue()) ? entry.getValue().getBytes(CHARSET) - : new byte[] {}); + bucket.put(entry.getKey(), + StringUtils.hasText(entry.getValue()) ? entry.getValue().getBytes(CHARSET) : new byte[] {}); } return bucket; } @@ -251,6 +246,7 @@ public class Bucket { } + @Nullable private String toUtf8String(byte[] raw) { try { diff --git a/src/main/java/org/springframework/data/redis/core/convert/IndexResolver.java b/src/main/java/org/springframework/data/redis/core/convert/IndexResolver.java index ce79e6c40..30d9b5d92 100644 --- a/src/main/java/org/springframework/data/redis/core/convert/IndexResolver.java +++ b/src/main/java/org/springframework/data/redis/core/convert/IndexResolver.java @@ -19,6 +19,7 @@ import java.util.Set; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; /** * {@link IndexResolver} extracts secondary index structures to be applied on a given path, {@link PersistentProperty} @@ -36,7 +37,7 @@ public interface IndexResolver { * @param value the actual value. Can be {@literal null}. * @return never {@literal null}. */ - Set resolveIndexesFor(TypeInformation typeInformation, Object value); + Set resolveIndexesFor(TypeInformation typeInformation, @Nullable Object value); /** * Resolves all indexes for given type information / value combination. @@ -47,6 +48,7 @@ public interface IndexResolver { * @param value the actual value. Can be {@literal null}. * @return never {@literal null}. */ - Set resolveIndexesFor(String keyspace, String path, TypeInformation typeInformation, Object value); + Set resolveIndexesFor(String keyspace, String path, TypeInformation typeInformation, + @Nullable Object value); } 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 215aa4b9b..040449dd7 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 @@ -22,6 +22,7 @@ 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; @@ -153,8 +154,8 @@ public class KeyspaceConfiguration { private final String keyspace; private final Class type; private final boolean inherit; - private Long timeToLive; - private String timeToLivePropertyName; + private @Nullable Long timeToLive; + private @Nullable String timeToLivePropertyName; public KeyspaceSettings(Class type, String keyspace) { this(type, keyspace, true); @@ -183,6 +184,7 @@ public class KeyspaceConfiguration { this.timeToLive = timeToLive; } + @Nullable public Long getTimeToLive() { return timeToLive; } @@ -191,6 +193,7 @@ public class KeyspaceConfiguration { timeToLivePropertyName = propertyName; } + @Nullable public String getTimeToLivePropertyName() { return timeToLivePropertyName; } 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 5774d0551..c994d68f3 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 @@ -22,6 +22,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -33,13 +34,13 @@ import org.springframework.util.Assert; */ public class RedisData { - private String keyspace; - private String id; + private @Nullable String keyspace; + private @Nullable String id; private Bucket bucket; private Set indexedData; - private Long timeToLive; + private @Nullable Long timeToLive; /** * Creates new {@link RedisData} with empty {@link Bucket}. @@ -81,6 +82,7 @@ public class RedisData { /** * @return */ + @Nullable public String getId() { return this.id; } @@ -90,6 +92,7 @@ public class RedisData { * * @return {@literal null} if not set. */ + @Nullable public Long getTimeToLive() { return timeToLive; } @@ -122,6 +125,7 @@ public class RedisData { /** * @return */ + @Nullable public String getKeyspace() { return keyspace; } 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 a08515727..0fe113461 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 @@ -32,6 +32,7 @@ import org.springframework.expression.BeanResolver; import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -47,7 +48,7 @@ public class SpelIndexResolver implements IndexResolver { private final SpelExpressionParser parser; private final RedisMappingContext mappingContext; - private BeanResolver beanResolver; + private @Nullable BeanResolver beanResolver; private Map expressionCache; @@ -79,7 +80,7 @@ public class SpelIndexResolver 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) { if (value == null) { return Collections.emptySet(); 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 new file mode 100644 index 000000000..d064994da --- /dev/null +++ b/src/main/java/org/springframework/data/redis/core/convert/package-info.java @@ -0,0 +1,5 @@ +/** + * Converters for Redis repository support utilizing mapping metadata. + */ +@org.springframework.lang.NonNullApi +package org.springframework.data.redis.core.convert; 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 08563c315..0d6f25082 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 @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -36,7 +37,7 @@ public abstract class RedisIndexDefinition implements IndexDefinition { private final String indexName; private final String path; private List> conditions; - private IndexValueTransformer valueTransformer; + private @Nullable IndexValueTransformer valueTransformer; /** * Creates new {@link RedisIndexDefinition}. 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 new file mode 100644 index 000000000..3c348dc53 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/core/index/package-info.java @@ -0,0 +1,5 @@ +/** + * Abstractions for Redis secondary indexes. + */ +@org.springframework.lang.NonNullApi +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 59f8aed32..42d4e2855 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 @@ -22,6 +22,7 @@ import org.springframework.data.mapping.MappingException; import org.springframework.data.redis.core.TimeToLive; import org.springframework.data.redis.core.TimeToLiveAccessor; import org.springframework.data.util.TypeInformation; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -74,6 +75,7 @@ public class BasicRedisPersistentEntity extends BasicKeyValuePersistentEntity * @see org.springframework.data.redis.core.mapping.RedisPersistentEntity#getExplicitTimeToLiveProperty() */ @Override + @Nullable public RedisPersistentProperty getExplicitTimeToLiveProperty() { return this.getPersistentProperty(TimeToLive.class); } @@ -83,6 +85,7 @@ public class BasicRedisPersistentEntity extends BasicKeyValuePersistentEntity * @see org.springframework.data.mapping.model.BasicPersistentEntity#returnPropertyIfBetterIdPropertyCandidateOrNull(org.springframework.data.mapping.PersistentProperty) */ @Override + @Nullable protected RedisPersistentProperty returnPropertyIfBetterIdPropertyCandidateOrNull(RedisPersistentProperty property) { Assert.notNull(property, "Property must not be null!"); 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 27e274500..2f0a28ab4 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 @@ -41,6 +41,7 @@ import org.springframework.data.redis.core.convert.MappingConfiguration; import org.springframework.data.redis.core.convert.RedisCustomConversions; import org.springframework.data.redis.core.index.IndexConfiguration; 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.NumberUtils; @@ -61,7 +62,7 @@ public class RedisMappingContext extends KeyValueMappingContext extends KeyValuePersistentEntityRedis with Spring concepts. - * - *

Provides template support and callback for low-level access. + * Core package for integrating Redis with Spring concepts. + *

+ * Provides template support and callback for low-level access. */ +@org.springframework.lang.NonNullApi package org.springframework.data.redis.core; - diff --git a/src/main/java/org/springframework/data/redis/core/query/DefaultSortCriterion.java b/src/main/java/org/springframework/data/redis/core/query/DefaultSortCriterion.java index de0d0b46a..d03a8a5d1 100644 --- a/src/main/java/org/springframework/data/redis/core/query/DefaultSortCriterion.java +++ b/src/main/java/org/springframework/data/redis/core/query/DefaultSortCriterion.java @@ -20,21 +20,23 @@ 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 implementation for {@link SortCriterion}. * * @author Costin Leau + * @author Christoph Strobl */ class DefaultSortCriterion implements SortCriterion { private final K key; - private String by; + private @Nullable String by; private final List getKeys = new ArrayList<>(4); - private Range limit; - private Order order; - private Boolean alpha; + private @Nullable Range limit; + private @Nullable Order order; + private @Nullable Boolean alpha; DefaultSortCriterion(K key) { this.key = key; @@ -54,6 +56,8 @@ class DefaultSortCriterion implements SortCriterion { return this; } + // TODO: check if we can use differnt range from SD commons here?? + public SortCriterion limit(Range range) { this.limit = range; return this; 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 d2c434a6d..ab0db10ef 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 @@ -1,5 +1,6 @@ /** * Query package for Redis template. */ +@org.springframework.lang.NonNullApi package org.springframework.data.redis.core.query; 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 7723ef0ed..894891bae 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 @@ -19,6 +19,7 @@ import java.io.IOException; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; +import org.springframework.lang.Nullable; import org.springframework.scripting.ScriptSource; import org.springframework.scripting.support.ResourceScriptSource; import org.springframework.scripting.support.StaticScriptSource; @@ -36,9 +37,9 @@ import org.springframework.util.Assert; */ public class DefaultRedisScript implements RedisScript, InitializingBean { - private ScriptSource scriptSource; - private String sha1; - private Class resultType; + private @Nullable ScriptSource scriptSource; + private @Nullable String sha1; + private @Nullable Class resultType; private final Object shaModifiedMonitor = new Object(); /** @@ -96,6 +97,7 @@ public class DefaultRedisScript implements RedisScript, InitializingBean { * (non-Javadoc) * @see org.springframework.data.redis.core.script.RedisScript#getResultType() */ + @Nullable public Class getResultType() { return this.resultType; } diff --git a/src/main/java/org/springframework/data/redis/core/script/RedisScript.java b/src/main/java/org/springframework/data/redis/core/script/RedisScript.java index 68e42a1c0..f2f12b672 100644 --- a/src/main/java/org/springframework/data/redis/core/script/RedisScript.java +++ b/src/main/java/org/springframework/data/redis/core/script/RedisScript.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.core.script; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -37,6 +38,7 @@ public interface RedisScript { * @return The script result type. Should be one of Long, Boolean, List, or deserialized value type. {@literal null} * if the script returns a throw-away status (i.e "OK"). */ + @Nullable Class getResultType(); /** 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 new file mode 100644 index 000000000..ae6deb18f --- /dev/null +++ b/src/main/java/org/springframework/data/redis/core/script/package-info.java @@ -0,0 +1,5 @@ +/** + * Lua script execution abstraction. + */ +@org.springframework.lang.NonNullApi +package org.springframework.data.redis.core.script; 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 new file mode 100644 index 000000000..64571585d --- /dev/null +++ b/src/main/java/org/springframework/data/redis/core/types/package-info.java @@ -0,0 +1,5 @@ +/** + * Redis domain specific types. + */ +@org.springframework.lang.NonNullApi +package org.springframework.data.redis.core.types; 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 48420b78c..358dfbc10 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 @@ -1,7 +1,5 @@ /** - * Dedicated support package for Redis hashes. - * - * Provides mapping of objects to hashes/maps (and vice versa). + * Dedicated support package for Redis hashes. Provides mapping of objects to hashes/maps (and vice versa). */ +@org.springframework.lang.NonNullApi package org.springframework.data.redis.hash; - 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 3c4b63066..8d047af3b 100644 --- a/src/main/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListener.java +++ b/src/main/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListener.java @@ -20,6 +20,7 @@ import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.core.RedisKeyExpiredEvent; +import org.springframework.lang.Nullable; /** * {@link MessageListener} publishing {@link RedisKeyExpiredEvent}s via {@link ApplicationEventPublisher} by listening @@ -31,7 +32,7 @@ import org.springframework.data.redis.core.RedisKeyExpiredEvent; public class KeyExpirationEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware { - private ApplicationEventPublisher publisher; + private @Nullable ApplicationEventPublisher publisher; private static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic("__keyevent@*__:expired"); /** 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 ab9535bb9..7b5c92cc9 100644 --- a/src/main/java/org/springframework/data/redis/listener/KeyspaceEventMessageListener.java +++ b/src/main/java/org/springframework/data/redis/listener/KeyspaceEventMessageListener.java @@ -22,7 +22,9 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -54,9 +56,9 @@ public abstract class KeyspaceEventMessageListener implements MessageListener, I * @see org.springframework.data.redis.connection.MessageListener#onMessage(org.springframework.data.redis.connection.Message, byte[]) */ @Override - public void onMessage(Message message, byte[] pattern) { + public void onMessage(Message message, @Nullable byte[] pattern) { - if (message == null || message.getChannel() == null || message.getBody() == null) { + if (message == null || ObjectUtils.isEmpty(message.getChannel()) || ObjectUtils.isEmpty(message.getBody())) { return; } diff --git a/src/main/java/org/springframework/data/redis/listener/RedisMessageListenerContainer.java b/src/main/java/org/springframework/data/redis/listener/RedisMessageListenerContainer.java index db4110601..10d9990fb 100644 --- a/src/main/java/org/springframework/data/redis/listener/RedisMessageListenerContainer.java +++ b/src/main/java/org/springframework/data/redis/listener/RedisMessageListenerContainer.java @@ -44,6 +44,7 @@ import org.springframework.data.redis.connection.Subscription; import org.springframework.data.redis.connection.util.ByteArrayWrapper; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.lang.Nullable; import org.springframework.scheduling.SchedulingAwareRunnable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -92,15 +93,15 @@ public class RedisMessageListenerContainer implements InitializingBean, Disposab private long initWait = TimeUnit.SECONDS.toMillis(5); - private Executor subscriptionExecutor; + private @Nullable Executor subscriptionExecutor; - private Executor taskExecutor; + private @Nullable Executor taskExecutor; - private RedisConnectionFactory connectionFactory; + private @Nullable RedisConnectionFactory connectionFactory; - private String beanName; + private @Nullable String beanName; - private ErrorHandler errorHandler; + private @Nullable ErrorHandler errorHandler; private final Object monitor = new Object(); // whether the container is running (or not) @@ -297,6 +298,7 @@ public class RedisMessageListenerContainer implements InitializingBean, Disposab * * @return Returns the connectionFactory */ + @Nullable public RedisConnectionFactory getConnectionFactory() { return connectionFactory; } @@ -305,6 +307,8 @@ public class RedisMessageListenerContainer implements InitializingBean, Disposab * @param connectionFactory The connectionFactory to set. */ public void setConnectionFactory(RedisConnectionFactory connectionFactory) { + + Assert.notNull(connectionFactory, "ConnectionFactory must not be null!"); this.connectionFactory = connectionFactory; } @@ -715,7 +719,7 @@ public class RedisMessageListenerContainer implements InitializingBean, Disposab } } - private volatile RedisConnection connection; + private volatile @Nullable RedisConnection connection; private boolean subscriptionTaskRunning = false; private final Object localMonitor = new Object(); private long subscriptionWait = TimeUnit.SECONDS.toMillis(5); @@ -940,7 +944,8 @@ public class RedisMessageListenerContainer implements InitializingBean, Disposab */ private class DispatchMessageListener implements MessageListener { - public void onMessage(Message message, byte[] pattern) { + @Override + public void onMessage(Message message, @Nullable byte[] pattern) { Collection listeners = null; // if it's a pattern, disregard channel 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 18b9a6a8a..8176953e7 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 @@ -31,6 +31,7 @@ import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -95,7 +96,7 @@ import org.springframework.util.StringUtils; */ public class MessageListenerAdapter implements InitializingBean, MessageListener { - + // TODO move this down. private class MethodInvoker { private final Object delegate; @@ -129,9 +130,9 @@ public class MessageListenerAdapter implements InitializingBean, MessageListener Class[] types = m.getParameterTypes(); Object[] args = // - types.length == 2 // - && types[0].isInstance(arguments[0]) // - && types[1].isInstance(arguments[1]) ? arguments : message; + types.length == 2 // + && types[0].isInstance(arguments[0]) // + && types[1].isInstance(arguments[1]) ? arguments : message; if (!types[0].isInstance(args[0])) { continue; @@ -161,15 +162,15 @@ public class MessageListenerAdapter implements InitializingBean, MessageListener /** Logger available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); - private volatile Object delegate; + private volatile @Nullable Object delegate; - private volatile MethodInvoker invoker; + private volatile @Nullable MethodInvoker invoker; private String defaultListenerMethod = ORIGINAL_DEFAULT_LISTENER_METHOD; - private RedisSerializer serializer; + private @Nullable RedisSerializer serializer; - private RedisSerializer stringSerializer; + private @Nullable RedisSerializer stringSerializer; /** * Create a new {@link MessageListenerAdapter} with default settings. @@ -220,6 +221,7 @@ public class MessageListenerAdapter implements InitializingBean, MessageListener * * @return message listening delegation */ + @Nullable public Object getDelegate() { return this.delegate; } @@ -284,8 +286,8 @@ public class MessageListenerAdapter implements InitializingBean, MessageListener * @param message the incoming Redis message * @see #handleListenerException */ - - public void onMessage(Message message, byte[] pattern) { + @Override + public void onMessage(Message message, @Nullable byte[] pattern) { try { // Check whether the delegate is a MessageListener impl itself. // In that case, the adapter will simply act as a pass-through. 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 50806356e..37aa45274 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 @@ -1,7 +1,6 @@ /** - * Message listener adapter package. - * The adapter delegates to target listener methods, converting messages to appropriate message content types - * (such as String or byte array) that get passed into listener methods. + * Message listener adapter package. The adapter delegates to target listener methods, converting messages to + * appropriate message content types (such as String or byte array) that get passed into listener methods. */ +@org.springframework.lang.NonNullApi 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 855cc5f5b..52912f83b 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 @@ -1,5 +1,5 @@ /** - * Base package for Redis message listener / pubsub container facility + * Base package for Redis message listener / pubsub container facility */ +@org.springframework.lang.NonNullApi 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 441d731df..bd4936a42 100644 --- a/src/main/java/org/springframework/data/redis/package-info.java +++ b/src/main/java/org/springframework/data/redis/package-info.java @@ -1,8 +1,7 @@ /** - * Root package for integrating Redis with Spring concepts. + * Root package for integrating Redis with Spring concepts. *

- * Provides Redis specific exception hierarchy on top of the {@code org.springframework.dao} package. - * + * Provides Redis specific exception hierarchy on top of the {@code org.springframework.dao} package. */ +@org.springframework.lang.NonNullApi package org.springframework.data.redis; - 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 85bc35bf6..97d838c0b 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 @@ -1,20 +1,5 @@ -/* - * Copyright 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. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - /** * CDI support for Redis specific repository implementation. */ +@org.springframework.lang.NonNullApi 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 new file mode 100644 index 000000000..33682f5ac --- /dev/null +++ b/src/main/java/org/springframework/data/redis/repository/configuration/package-info.java @@ -0,0 +1,5 @@ +/** + * Redis repository specific configuration and bean registration. + */ +@org.springframework.lang.NonNullApi +package org.springframework.data.redis.repository.configuration; 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 new file mode 100644 index 000000000..72facbc20 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/repository/core/package-info.java @@ -0,0 +1,5 @@ +/** + * Core domain entities for repository support. + */ +@org.springframework.lang.NonNullApi +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 new file mode 100644 index 000000000..db7ca62a1 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/repository/package-info.java @@ -0,0 +1,5 @@ +/** + * Redis specific implementation of repository support + */ +@org.springframework.lang.NonNullApi +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 e34418f81..c7c736489 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 @@ -24,6 +24,8 @@ import java.util.Set; 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; /** @@ -36,7 +38,7 @@ public class RedisOperationChain { private Set sismember = new LinkedHashSet<>(); private Set orSismember = new LinkedHashSet<>(); - private NearPath near; + private @Nullable NearPath near; public void sismember(String path, Object value) { sismember(new PathAndValue(path, value)); @@ -67,9 +69,12 @@ public class RedisOperationChain { } public void near(NearPath near) { + + Assert.notNull(near, "Near must not be null!"); this.near = near; } + @Nullable public NearPath getNear() { return near; } @@ -85,7 +90,7 @@ public class RedisOperationChain { this.values = Collections.singleton(singleValue); } - public PathAndValue(String path, Collection values) { + public PathAndValue(String path, @Nullable Collection values) { this.path = path; this.values = values != null ? values : Collections.emptySet(); @@ -148,7 +153,7 @@ public class RedisOperationChain { public static class NearPath extends PathAndValue { public NearPath(String path, Point point, Distance distance) { - super(path, Arrays. asList(point, distance)); + super(path, Arrays.asList(point, distance)); } public Point getPoint() { diff --git a/src/main/java/org/springframework/data/redis/repository/query/package-info.java b/src/main/java/org/springframework/data/redis/repository/query/package-info.java new file mode 100644 index 000000000..7be95016a --- /dev/null +++ b/src/main/java/org/springframework/data/redis/repository/query/package-info.java @@ -0,0 +1,5 @@ +/** + * Redis specific query execution engine. + */ +@org.springframework.lang.NonNullApi +package org.springframework.data.redis.repository.query; diff --git a/src/main/java/org/springframework/data/redis/repository/support/package-info.java b/src/main/java/org/springframework/data/redis/repository/support/package-info.java new file mode 100644 index 000000000..d2be454d6 --- /dev/null +++ b/src/main/java/org/springframework/data/redis/repository/support/package-info.java @@ -0,0 +1,5 @@ +/** + * Spring context specific factory support. + */ +@org.springframework.lang.NonNullApi +package org.springframework.data.redis.repository.support; diff --git a/src/main/java/org/springframework/data/redis/serializer/DefaultRedisElementReader.java b/src/main/java/org/springframework/data/redis/serializer/DefaultRedisElementReader.java index 59439f285..b4d810e06 100644 --- a/src/main/java/org/springframework/data/redis/serializer/DefaultRedisElementReader.java +++ b/src/main/java/org/springframework/data/redis/serializer/DefaultRedisElementReader.java @@ -19,6 +19,8 @@ import lombok.RequiredArgsConstructor; import java.nio.ByteBuffer; +import org.springframework.lang.Nullable; + /** * Default implementation of {@link RedisElementReader}. * @@ -29,7 +31,7 @@ import java.nio.ByteBuffer; @RequiredArgsConstructor class DefaultRedisElementReader implements RedisElementReader { - private final RedisSerializer serializer; + private final @Nullable RedisSerializer serializer; /* (non-Javadoc) * @see org.springframework.data.redis.serializer.RedisElementReader#read(java.nio.ByteBuffer) diff --git a/src/main/java/org/springframework/data/redis/serializer/DefaultRedisElementWriter.java b/src/main/java/org/springframework/data/redis/serializer/DefaultRedisElementWriter.java index 49fa19e0f..f404d732c 100644 --- a/src/main/java/org/springframework/data/redis/serializer/DefaultRedisElementWriter.java +++ b/src/main/java/org/springframework/data/redis/serializer/DefaultRedisElementWriter.java @@ -19,16 +19,19 @@ import lombok.RequiredArgsConstructor; import java.nio.ByteBuffer; +import org.springframework.lang.Nullable; + /** * Default implementation of {@link RedisElementWriter}. * * @author Mark Paluch + * @author Christoph Strobl * @since 2.0 */ @RequiredArgsConstructor class DefaultRedisElementWriter implements RedisElementWriter { - private final RedisSerializer serializer; + private final @Nullable RedisSerializer serializer; /* (non-Javadoc) * @see org.springframework.data.redis.serializer.RedisElementWriter#write(java.lang.Object) @@ -36,19 +39,19 @@ class DefaultRedisElementWriter implements RedisElementWriter { @Override public ByteBuffer write(T value) { - if (serializer == null) { - - if (value instanceof byte[]) { - return ByteBuffer.wrap((byte[]) value); - } - - if (value instanceof ByteBuffer) { - return (ByteBuffer) value; - } - - throw new IllegalStateException("Cannot serialize value without a serializer"); + if (serializer != null) { + return ByteBuffer.wrap(serializer.serialize((T) value)); } - return ByteBuffer.wrap(serializer.serialize((T) value)); + if (value instanceof byte[]) { + return ByteBuffer.wrap((byte[]) value); + } + + if (value instanceof ByteBuffer) { + return (ByteBuffer) value; + } + + throw new IllegalStateException("Cannot serialize value without a serializer"); + } } diff --git a/src/main/java/org/springframework/data/redis/serializer/DefaultRedisSerializationContext.java b/src/main/java/org/springframework/data/redis/serializer/DefaultRedisSerializationContext.java index 2fc1de814..772fd52f1 100644 --- a/src/main/java/org/springframework/data/redis/serializer/DefaultRedisSerializationContext.java +++ b/src/main/java/org/springframework/data/redis/serializer/DefaultRedisSerializationContext.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.serializer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -93,10 +94,10 @@ class DefaultRedisSerializationContext implements RedisSerializationContex */ static class DefaultRedisSerializationContextBuilder implements RedisSerializationContextBuilder { - private SerializationPair keyTuple; - private SerializationPair valueTuple; - private SerializationPair hashKeyTuple; - private SerializationPair hashValueTuple; + private @Nullable SerializationPair keyTuple; + private @Nullable SerializationPair valueTuple; + private @Nullable SerializationPair hashKeyTuple; + private @Nullable SerializationPair hashValueTuple; private SerializationPair stringTuple = SerializationPair.fromSerializer(new StringRedisSerializer()); /* (non-Javadoc) 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 3d000328c..f9ac7ad19 100644 --- a/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java @@ -18,6 +18,7 @@ package org.springframework.data.redis.serializer; import java.io.IOException; import org.springframework.cache.support.NullValue; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -87,7 +88,7 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer T deserialize(byte[] source, Class type) throws SerializationException { + public T deserialize(@Nullable byte[] source, Class type) throws SerializationException { Assert.notNull(type, "Deserialization type must not be null! Pleaes provide Object.class to make use of Jackson2 default typing."); diff --git a/src/main/java/org/springframework/data/redis/serializer/GenericToStringSerializer.java b/src/main/java/org/springframework/data/redis/serializer/GenericToStringSerializer.java index 666d53331..fd6532c90 100644 --- a/src/main/java/org/springframework/data/redis/serializer/GenericToStringSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/GenericToStringSerializer.java @@ -24,6 +24,7 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -61,7 +62,9 @@ public class GenericToStringSerializer implements RedisSerializer, BeanFac converter = new Converter(typeConverter); } - public T deserialize(byte[] bytes) { + @Override + public T deserialize(@Nullable byte[] bytes) { + if (bytes == null) { return null; } @@ -70,7 +73,8 @@ public class GenericToStringSerializer implements RedisSerializer, BeanFac return converter.convert(string, type); } - public byte[] serialize(T object) { + @Override + public byte[] serialize(@Nullable T object) { if (object == null) { return null; } @@ -83,7 +87,8 @@ public class GenericToStringSerializer implements RedisSerializer, BeanFac ConfigurableBeanFactory cFB = (ConfigurableBeanFactory) beanFactory; ConversionService conversionService = cFB.getConversionService(); - converter = (conversionService != null ? new Converter(conversionService) : new Converter(cFB.getTypeConverter())); + converter = (conversionService != null ? new Converter(conversionService) + : new Converter(cFB.getTypeConverter())); } } 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 c8b86c8ab..82eea9b32 100644 --- a/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java @@ -17,6 +17,7 @@ package org.springframework.data.redis.serializer; import java.nio.charset.Charset; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import com.fasterxml.jackson.databind.JavaType; @@ -62,7 +63,7 @@ public class Jackson2JsonRedisSerializer implements RedisSerializer { } @SuppressWarnings("unchecked") - public T deserialize(byte[] bytes) throws SerializationException { + public T deserialize(@Nullable byte[] bytes) throws SerializationException { if (SerializationUtils.isEmpty(bytes)) { return null; @@ -74,7 +75,8 @@ public class Jackson2JsonRedisSerializer implements RedisSerializer { } } - public byte[] serialize(Object t) throws SerializationException { + @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/JdkSerializationRedisSerializer.java b/src/main/java/org/springframework/data/redis/serializer/JdkSerializationRedisSerializer.java index e7fde0c23..0794e3e10 100644 --- a/src/main/java/org/springframework/data/redis/serializer/JdkSerializationRedisSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/JdkSerializationRedisSerializer.java @@ -20,6 +20,7 @@ import org.springframework.core.serializer.DefaultDeserializer; import org.springframework.core.serializer.DefaultSerializer; import org.springframework.core.serializer.support.DeserializingConverter; import org.springframework.core.serializer.support.SerializingConverter; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -71,7 +72,8 @@ public class JdkSerializationRedisSerializer implements RedisSerializer this.deserializer = deserializer; } - public Object deserialize(byte[] bytes) { + public Object deserialize(@Nullable byte[] bytes) { + if (SerializationUtils.isEmpty(bytes)) { return null; } @@ -83,7 +85,8 @@ public class JdkSerializationRedisSerializer implements RedisSerializer } } - public byte[] serialize(Object object) { + @Override + public byte[] serialize(@Nullable Object object) { if (object == null) { return SerializationUtils.EMPTY_ARRAY; } 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 0555f2ab9..0ca7380ca 100644 --- a/src/main/java/org/springframework/data/redis/serializer/OxmSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/OxmSerializer.java @@ -22,6 +22,7 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.springframework.beans.factory.InitializingBean; +import org.springframework.lang.Nullable; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; import org.springframework.util.Assert; @@ -34,12 +35,13 @@ import org.springframework.util.Assert; */ public class OxmSerializer implements InitializingBean, RedisSerializer { - private Marshaller marshaller; - private Unmarshaller unmarshaller; + private @Nullable Marshaller marshaller; + private @Nullable Unmarshaller unmarshaller; public OxmSerializer() {} public OxmSerializer(Marshaller marshaller, Unmarshaller unmarshaller) { + this.marshaller = marshaller; this.unmarshaller = unmarshaller; @@ -47,7 +49,8 @@ public class OxmSerializer implements InitializingBean, RedisSerializer } public void afterPropertiesSet() { - Assert.notNull(marshaller, "non-null marshaller required"); + + Assert.notNull(marshaller, "non-null marshaller required"); // TODO: use Illegal state exception Assert.notNull(unmarshaller, "non-null unmarshaller required"); } @@ -65,7 +68,8 @@ public class OxmSerializer implements InitializingBean, RedisSerializer this.unmarshaller = unmarshaller; } - public Object deserialize(byte[] bytes) throws SerializationException { + @Override + public Object deserialize(@Nullable byte[] bytes) throws SerializationException { if (SerializationUtils.isEmpty(bytes)) { return null; } @@ -77,7 +81,8 @@ public class OxmSerializer implements InitializingBean, RedisSerializer } } - public byte[] serialize(Object t) throws SerializationException { + @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/RedisElementReader.java b/src/main/java/org/springframework/data/redis/serializer/RedisElementReader.java index dc39b0e81..abba654ff 100644 --- a/src/main/java/org/springframework/data/redis/serializer/RedisElementReader.java +++ b/src/main/java/org/springframework/data/redis/serializer/RedisElementReader.java @@ -17,6 +17,7 @@ package org.springframework.data.redis.serializer; import java.nio.ByteBuffer; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -34,8 +35,9 @@ public interface RedisElementReader { * Deserialize a {@link ByteBuffer} into the according type. * * @param buffer must not be {@literal null}. - * @return the deserialized value. + * @return the deserialized value. Can be {@literal null}. */ + @Nullable T read(ByteBuffer buffer); /** diff --git a/src/main/java/org/springframework/data/redis/serializer/RedisSerializer.java b/src/main/java/org/springframework/data/redis/serializer/RedisSerializer.java index 434fa73ad..f1c4b0496 100644 --- a/src/main/java/org/springframework/data/redis/serializer/RedisSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/RedisSerializer.java @@ -15,6 +15,8 @@ */ package org.springframework.data.redis.serializer; +import org.springframework.lang.Nullable; + /** * Basic interface serialization and deserialization of Objects to byte arrays (binary data). It is recommended that * implementations are designed to handle null objects/empty arrays on serialization and deserialization side. Note that @@ -22,22 +24,25 @@ package org.springframework.data.redis.serializer; * * @author Mark Pollack * @author Costin Leau + * @author Christoph Strobl */ public interface RedisSerializer { /** * Serialize the given object to binary data. * - * @param t object to serialize - * @return the equivalent binary data + * @param t object to serialize. Can be {@literal null}. + * @return the equivalent binary data. Can be {@literal null}. */ - byte[] serialize(T t) throws SerializationException; + @Nullable + byte[] serialize(@Nullable T t) throws SerializationException; /** * Deserialize an object from the given binary data. * - * @param bytes object binary representation - * @return the equivalent object instance + * @param bytes object binary representation. Can be {@literal null}. + * @return the equivalent object instance. Can be {@literal null}. */ - T deserialize(byte[] bytes) throws SerializationException; + @Nullable + T deserialize(@Nullable byte[] bytes) throws SerializationException; } 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 59be7f1c4..a5fcfeb4d 100644 --- a/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java +++ b/src/main/java/org/springframework/data/redis/serializer/SerializationUtils.java @@ -17,12 +17,16 @@ package org.springframework.data.redis.serializer; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.springframework.core.CollectionFactory; +import org.springframework.lang.Nullable; + /** * Utility class with various serialization-related methods. * @@ -32,16 +36,16 @@ public abstract class SerializationUtils { static final byte[] EMPTY_ARRAY = new byte[0]; - static boolean isEmpty(byte[] data) { + static boolean isEmpty(@Nullable byte[] data) { return (data == null || data.length == 0); } @SuppressWarnings("unchecked") - static > T deserializeValues(Collection rawValues, Class type, + static > T deserializeValues(@Nullable Collection rawValues, Class type, RedisSerializer redisSerializer) { // connection in pipeline/multi mode if (rawValues == null) { - return null; + return (T) CollectionFactory.createCollection(type, 0); } Collection values = (List.class.isAssignableFrom(type) ? new ArrayList<>(rawValues.size()) @@ -54,23 +58,25 @@ public abstract class SerializationUtils { } @SuppressWarnings("unchecked") - public static Set deserialize(Set rawValues, RedisSerializer redisSerializer) { + public static Set deserialize(@Nullable Set rawValues, RedisSerializer redisSerializer) { return deserializeValues(rawValues, Set.class, redisSerializer); } @SuppressWarnings("unchecked") - public static List deserialize(List rawValues, RedisSerializer redisSerializer) { + public static List deserialize(@Nullable List rawValues, RedisSerializer redisSerializer) { return deserializeValues(rawValues, List.class, redisSerializer); } @SuppressWarnings("unchecked") - public static Collection deserialize(Collection rawValues, RedisSerializer redisSerializer) { + public static Collection deserialize(@Nullable Collection rawValues, + RedisSerializer redisSerializer) { return deserializeValues(rawValues, List.class, redisSerializer); } - public static Map deserialize(Map rawValues, RedisSerializer redisSerializer) { + public static Map deserialize(@Nullable Map rawValues, RedisSerializer redisSerializer) { + if (rawValues == null) { - return null; + return Collections.emptyMap(); } Map ret = new LinkedHashMap<>(rawValues.size()); for (Map.Entry entry : rawValues.entrySet()) { @@ -80,17 +86,18 @@ public abstract class SerializationUtils { } @SuppressWarnings("unchecked") - public static Map deserialize(Map rawValues, RedisSerializer hashKeySerializer, - RedisSerializer hashValueSerializer) { + public static Map deserialize(@Nullable Map rawValues, + RedisSerializer hashKeySerializer, RedisSerializer hashValueSerializer) { + if (rawValues == null) { - return null; + return Collections.emptyMap(); } 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()) : (HV) entry - .getValue(); + HV value = hashValueSerializer != null ? (HV) hashValueSerializer.deserialize(entry.getValue()) + : (HV) entry.getValue(); map.put(key, value); } return map; 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 5aa898840..3c1a5c22a 100644 --- a/src/main/java/org/springframework/data/redis/serializer/StringRedisSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/StringRedisSerializer.java @@ -17,6 +17,7 @@ package org.springframework.data.redis.serializer; import java.nio.charset.Charset; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -43,11 +44,11 @@ public class StringRedisSerializer implements RedisSerializer { this.charset = charset; } - public String deserialize(byte[] bytes) { + public String deserialize(@Nullable byte[] bytes) { return (bytes == null ? null : new String(bytes, charset)); } - public byte[] serialize(String string) { + 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 3956423a5..f11776cf2 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 @@ -1,5 +1,5 @@ /** - * Serialization/Deserialization package for converting Object to (and from) binary data. + * Serialization/Deserialization package for converting Object to (and from) binary data. */ +@org.springframework.lang.NonNullApi package org.springframework.data.redis.serializer; - 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 872a8018a..ee64b49b2 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 @@ -1,5 +1,5 @@ /** - * Small toolkit mirroring the {@code java.util.atomic} package in Redis. + * Small toolkit mirroring the {@code java.util.atomic} package in Redis. */ +@org.springframework.lang.NonNullApi 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 b79622fc9..1d942c22f 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 @@ -21,6 +21,7 @@ import java.util.Date; import java.util.concurrent.TimeUnit; import org.springframework.data.redis.core.RedisOperations; +import org.springframework.lang.Nullable; /** * Base implementation for {@link RedisCollection}. Provides a skeletal implementation. Note that the collection support @@ -124,7 +125,7 @@ public abstract class AbstractRedisCollection extends AbstractCollection i key = newKey; } - protected void checkResult(Object obj) { + protected void checkResult(@Nullable Object obj) { if (obj == null) { throw new IllegalStateException("Cannot read collection with Redis connection in pipeline/multi-exec mode"); } 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 dc822b98b..da32533e7 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,5 +1,5 @@ /* - * 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. @@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.core.BoundListOperations; import org.springframework.data.redis.core.RedisOperations; +import org.springframework.lang.Nullable; /** * Default implementation for {@link RedisList}. Suitable for not just lists, but also queues (FIFO ordering) or stacks @@ -34,6 +35,7 @@ import org.springframework.data.redis.core.RedisOperations; * 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 */ public class DefaultRedisList extends AbstractRedisCollection implements RedisList { @@ -220,6 +222,7 @@ public class DefaultRedisList extends AbstractRedisCollection implements R } public E set(int index, E e) { + E object = get(index); listOps.set(index, e); return object; @@ -235,8 +238,9 @@ public class DefaultRedisList extends AbstractRedisCollection implements R public E element() { E value = peek(); - if (value == null) + if (value == null) { throw new NoSuchElementException(); + } return value; } @@ -247,18 +251,22 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return true; } + @Nullable public E peek() { return listOps.index(0); } + @Nullable public E poll() { return listOps.leftPop(); } public E remove() { + E value = poll(); - if (value == null) + if (value == null) { throw new NoSuchElementException(); + } return value; } @@ -304,23 +312,28 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return true; } + @Nullable public E peekFirst() { return peek(); } + @Nullable public E peekLast() { return listOps.index(-1); } + @Nullable public E pollFirst() { return poll(); } + @Nullable public E pollLast() { return listOps.rightPop(); } public E pop() { + E e = poll(); if (e == null) { throw new NoSuchElementException(); @@ -356,7 +369,6 @@ public class DefaultRedisList extends AbstractRedisCollection implements R // // BlockingQueue // - public int drainTo(Collection c, int maxElements) { if (this.equals(c)) { throw new IllegalArgumentException("Cannot drain a queue to itself"); @@ -380,6 +392,7 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return offer(e); } + @Nullable public E poll(long timeout, TimeUnit unit) throws InterruptedException { E element = listOps.leftPop(timeout, unit); return (element == null ? null : element); @@ -393,6 +406,7 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return Integer.MAX_VALUE; } + @Nullable public E take() throws InterruptedException { return poll(0, TimeUnit.SECONDS); } @@ -409,10 +423,12 @@ public class DefaultRedisList extends AbstractRedisCollection implements R return offerLast(e); } + @Nullable public E pollFirst(long timeout, TimeUnit unit) throws InterruptedException { return poll(timeout, unit); } + @Nullable public E pollLast(long timeout, TimeUnit unit) throws InterruptedException { E element = listOps.rightPop(timeout, unit); return (element == null ? null : element); @@ -426,10 +442,12 @@ public class DefaultRedisList extends AbstractRedisCollection implements R put(e); } + @Nullable public E takeFirst() throws InterruptedException { return take(); } + @Nullable public E takeLast() throws InterruptedException { return pollLast(0, TimeUnit.SECONDS); } 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 cdeaef4f2..e89a7ba96 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 @@ -30,12 +30,14 @@ import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.SessionCallback; +import org.springframework.lang.Nullable; /** * Default implementation for {@link RedisMap}. Note that the current implementation doesn't provide the same locking * semantics across all methods. In highly concurrent environments, race conditions might appear. * * @author Costin Leau + * @author Christoph Strobl */ public class DefaultRedisMap implements RedisMap { @@ -44,9 +46,10 @@ public class DefaultRedisMap implements RedisMap { private class DefaultRedisMapEntry implements Map.Entry { private K key; - private V value; + private @Nullable V value; + + public DefaultRedisMapEntry(K key, @Nullable V value) { - public DefaultRedisMapEntry(K key, V value) { this.key = key; this.value = value; } @@ -55,11 +58,12 @@ public class DefaultRedisMap implements RedisMap { return key; } + @Nullable public V getValue() { return value; } - public V setValue(V value) { + public V setValue(@Nullable V value) { throw new UnsupportedOperationException(); } } @@ -125,6 +129,7 @@ public class DefaultRedisMap implements RedisMap { return entries; } + @Nullable public V get(Object key) { return hashOps.get(key); } @@ -147,6 +152,7 @@ public class DefaultRedisMap implements RedisMap { hashOps.putAll(m); } + @Nullable public V remove(Object key) { V v = get(key); hashOps.delete(key); @@ -186,6 +192,7 @@ public class DefaultRedisMap implements RedisMap { return sb.toString(); } + @Nullable public V putIfAbsent(K key, V value) { return (hashOps.putIfAbsent(key, value) ? null : get(key)); } @@ -214,7 +221,7 @@ public class DefaultRedisMap implements RedisMap { }); } - public boolean replace(final K key, final V oldValue, final V newValue) { + public boolean replace(final K key, V oldValue, V newValue) { if (oldValue == null || newValue == null) { throw new NullPointerException(); } @@ -238,6 +245,7 @@ public class DefaultRedisMap implements RedisMap { }); } + @Nullable public V replace(final K key, final V value) { if (value == null) { throw new NullPointerException(); @@ -290,7 +298,7 @@ public class DefaultRedisMap implements RedisMap { return hashOps.getType(); } - private void checkResult(Object obj) { + private void checkResult(@Nullable Object obj) { if (obj == null) { throw new IllegalStateException("Cannot read collection with Redis connection in pipeline/multi-exec mode"); } 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 97e164467..59335c227 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 @@ -225,8 +225,9 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R checkResult(members); Iterator iterator = members.iterator(); - if (iterator.hasNext()) + if (iterator.hasNext()) { return iterator.next(); + } throw new NoSuchElementException(); } @@ -234,8 +235,9 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R Set members = boundZSetOps.reverseRange(0, 0); checkResult(members); Iterator iterator = members.iterator(); - if (iterator.hasNext()) + if (iterator.hasNext()) { return iterator.next(); + } throw new NoSuchElementException(); } diff --git a/src/main/java/org/springframework/data/redis/support/collections/RedisCollectionFactoryBean.java b/src/main/java/org/springframework/data/redis/support/collections/RedisCollectionFactoryBean.java index 110751d48..22a5afae5 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/RedisCollectionFactoryBean.java +++ b/src/main/java/org/springframework/data/redis/support/collections/RedisCollectionFactoryBean.java @@ -20,6 +20,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -72,11 +73,11 @@ public class RedisCollectionFactoryBean implements InitializingBean, BeanNameAwa abstract DataType dataType(); } - private RedisStore store; - private CollectionType type = null; - private RedisTemplate template; - private String key; - private String beanName; + private @Nullable RedisStore store; + private @Nullable CollectionType type = null; + private @Nullable RedisTemplate template; + private @Nullable String key; + private @Nullable String beanName; public void afterPropertiesSet() { if (!StringUtils.hasText(key)) { diff --git a/src/main/java/org/springframework/data/redis/support/collections/RedisIterator.java b/src/main/java/org/springframework/data/redis/support/collections/RedisIterator.java index 569803991..049e6bba9 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/RedisIterator.java +++ b/src/main/java/org/springframework/data/redis/support/collections/RedisIterator.java @@ -17,6 +17,8 @@ package org.springframework.data.redis.support.collections; import java.util.Iterator; +import org.springframework.lang.Nullable; + /** * Iterator extension for Redis collection removal. * @@ -26,7 +28,7 @@ abstract class RedisIterator implements Iterator { private final Iterator delegate; - private E item; + private @Nullable E item; /** * Constructs a new RedisIterator instance. diff --git a/src/main/java/org/springframework/data/redis/support/collections/RedisStore.java b/src/main/java/org/springframework/data/redis/support/collections/RedisStore.java index 797b5e412..7620f0c77 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/RedisStore.java +++ b/src/main/java/org/springframework/data/redis/support/collections/RedisStore.java @@ -29,7 +29,7 @@ public interface RedisStore extends BoundKeyOperations { /** * Returns the underlying Redis operations used by the backing implementation. * - * @return operations + * @return operations never {@literal null}. */ RedisOperations getOperations(); } 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 a87ab4c74..946aef46f 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 @@ -1,12 +1,15 @@ /** * Package providing implementations for most of the {@code java.util} collections on top of Redis. *

- * For indexed collections, such as {@link java.util.List}, {@link java.util.Queue} or {@link java.util.Deque} - * consider {@link org.springframework.data.redis.support.collections.RedisList}.

- * For collections without duplicates the obvious candidate is {@link org.springframework.data.redis.support.collections.RedisSet}. Use - * {@link org.springframework.data.redis.support.collections.RedisZSet} if a - * certain order is required.

- * Lastly, for key/value associations {@link org.springframework.data.redis.support.collections.RedisMap} providing a Map-like abstraction on top of a Redis hash. + * For indexed collections, such as {@link java.util.List}, {@link java.util.Queue} or {@link java.util.Deque} consider + * {@link org.springframework.data.redis.support.collections.RedisList}. + *

+ * For collections without duplicates the obvious candidate is + * {@link org.springframework.data.redis.support.collections.RedisSet}. Use + * {@link org.springframework.data.redis.support.collections.RedisZSet} if a certain order is required. + *

+ * Lastly, for key/value associations {@link org.springframework.data.redis.support.collections.RedisMap} providing a + * Map-like abstraction on top of a Redis hash. */ +@org.springframework.lang.NonNullApi 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 6635f4edc..22350f2a6 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 @@ -1,5 +1,5 @@ /** * Classes supporting the Redis packages, such as collection or atomic counters. */ +@org.springframework.lang.NonNullApi 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 36d966c1f..3a718bed7 100644 --- a/src/main/java/org/springframework/data/redis/util/ByteUtils.java +++ b/src/main/java/org/springframework/data/redis/util/ByteUtils.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.List; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; /** * Some handy methods for dealing with byte arrays. @@ -59,7 +60,7 @@ public final class ByteUtils { public static byte[][] split(byte[] source, int c) { - if (source == null || source.length == 0) { + if (ObjectUtils.isEmpty(source)) { return new byte[][] {}; } 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 new file mode 100644 index 000000000..3c8b91f8d --- /dev/null +++ b/src/main/java/org/springframework/data/redis/util/package-info.java @@ -0,0 +1,5 @@ +/** + * Commonly used stuff for data manipulation throughout different driver specific implementations. + */ +@org.springframework.lang.NonNullApi +package org.springframework.data.redis.util; diff --git a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java index 7a211ee15..fc1e269e0 100644 --- a/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/connection/AbstractConnectionIntegrationTests.java @@ -643,7 +643,6 @@ public abstract class AbstractConnectionIntegrationTests { MessageListener listener = (message, pattern) -> { messages.add(message); - System.out.println("Received message '" + new String(message.getBody()) + "'"); }; Thread th = new Thread(() -> { @@ -1354,8 +1353,7 @@ public abstract class AbstractConnectionIntegrationTests { actual.add(connection.sAdd("myset", "foo")); actual.add(connection.sAdd("myset", "bar")); actual.add(connection.sMembers("myset")); - verifyResults( - Arrays.asList(new Object[] { 1l, 1l, new HashSet<>(Arrays.asList(new String[] { "foo", "bar" })) })); + verifyResults(Arrays.asList(new Object[] { 1l, 1l, new HashSet<>(Arrays.asList(new String[] { "foo", "bar" })) })); } @Test @@ -1363,8 +1361,8 @@ public abstract class AbstractConnectionIntegrationTests { actual.add(connection.sAdd("myset", "foo", "bar")); actual.add(connection.sAdd("myset", "baz")); actual.add(connection.sMembers("myset")); - verifyResults(Arrays - .asList(new Object[] { 2l, 1l, new HashSet<>(Arrays.asList(new String[] { "foo", "bar", "baz" })) })); + verifyResults( + Arrays.asList(new Object[] { 2l, 1l, new HashSet<>(Arrays.asList(new String[] { "foo", "bar", "baz" })) })); } @Test @@ -1391,8 +1389,7 @@ public abstract class AbstractConnectionIntegrationTests { actual.add(connection.sAdd("otherset", "bar")); actual.add(connection.sDiffStore("thirdset", "myset", "otherset")); actual.add(connection.sMembers("thirdset")); - verifyResults( - Arrays.asList(new Object[] { 1l, 1l, 1l, 1l, new HashSet<>(Collections.singletonList("foo")) })); + verifyResults(Arrays.asList(new Object[] { 1l, 1l, 1l, 1l, new HashSet<>(Collections.singletonList("foo")) })); } @Test @@ -1411,8 +1408,7 @@ public abstract class AbstractConnectionIntegrationTests { actual.add(connection.sAdd("otherset", "bar")); actual.add(connection.sInterStore("thirdset", "myset", "otherset")); actual.add(connection.sMembers("thirdset")); - verifyResults( - Arrays.asList(new Object[] { 1l, 1l, 1l, 1l, new HashSet<>(Collections.singletonList("bar")) })); + verifyResults(Arrays.asList(new Object[] { 1l, 1l, 1l, 1l, new HashSet<>(Collections.singletonList("bar")) })); } @Test @@ -1438,8 +1434,7 @@ public abstract class AbstractConnectionIntegrationTests { actual.add(connection.sAdd("myset", "foo")); actual.add(connection.sAdd("myset", "bar")); actual.add(connection.sPop("myset")); - assertTrue( - new HashSet<>(Arrays.asList(new String[] { "foo", "bar" })).contains((String) getResults().get(2))); + assertTrue(new HashSet<>(Arrays.asList(new String[] { "foo", "bar" })).contains((String) getResults().get(2))); } @Test // DATAREDIS-688 @@ -2212,19 +2207,12 @@ public abstract class AbstractConnectionIntegrationTests { assertThat(values, not(hasItems("a", "b", "c", "d"))); } - @Test // DATAREDIS-316 + @Test(expected = IllegalArgumentException.class) // DATAREDIS-316, DATAREDIS-692 @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) - public void setWithExpirationAndNullOpionShouldSetTtlWhenKeyDoesNotExist() { + public void setWithExpirationAndNullOpionShouldThrowException() { String key = "exp-" + UUID.randomUUID(); connection.set(key, "foo", Expiration.milliseconds(500), null); - - actual.add(connection.exists(key)); - actual.add(connection.pTtl(key)); - - List result = getResults(); - assertThat(result.get(0), is(Boolean.TRUE)); - assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(500d, 499d))); } @Test // DATAREDIS-316 @@ -2329,19 +2317,12 @@ public abstract class AbstractConnectionIntegrationTests { assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-2, 0))); } - @Test // DATAREDIS-316 + @Test(expected = IllegalArgumentException.class) // DATAREDIS-316, DATAREDIS-692 @WithRedisDriver({ RedisDriver.JEDIS, RedisDriver.LETTUCE }) - public void setWithNullExpirationAndUpsertOpionShouldSetTtlWhenKeyDoesNotExist() { + public void setWithNullExpirationAndUpsertOpionShouldThrowException() { String key = "exp-" + UUID.randomUUID(); connection.set(key, "foo", null, SetOption.upsert()); - - actual.add(connection.exists(key)); - actual.add(connection.pTtl(key)); - - List result = getResults(); - assertThat(result.get(0), is(Boolean.TRUE)); - assertThat(((Long) result.get(1)).doubleValue(), is(closeTo(-1, 0))); } @Test // DATAREDIS-316 diff --git a/src/test/java/org/springframework/data/redis/connection/ClusterCommandExecutorUnitTests.java b/src/test/java/org/springframework/data/redis/connection/ClusterCommandExecutorUnitTests.java index 29289086b..2ac25c1ca 100644 --- a/src/test/java/org/springframework/data/redis/connection/ClusterCommandExecutorUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/ClusterCommandExecutorUnitTests.java @@ -78,7 +78,7 @@ public class ClusterCommandExecutorUnitTests { static final RedisClusterNode CLUSTER_NODE_2_LOOKUP = RedisClusterNode.newRedisClusterNode() .withId("0f2ee5df45d18c50aca07228cc18b1da96fd5e84").build(); - static final RedisClusterNode UNKNOWN_CLUSTER_NODE = new RedisClusterNode("8.8.8.8", 7379, null); + static final RedisClusterNode UNKNOWN_CLUSTER_NODE = new RedisClusterNode("8.8.8.8", 7379, SlotRange.empty()); private ClusterCommandExecutor executor; diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java index df58c2be3..b5fc03e0d 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionTests.java @@ -22,6 +22,7 @@ import static org.springframework.data.redis.connection.RedisGeoCommands.Distanc import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*; import static org.springframework.data.redis.core.ScanOptions.*; +import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPool; @@ -199,7 +200,7 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests { nativeConnection.set(KEY_1, VALUE_1); nativeConnection.set(KEY_2, VALUE_2); - Set keysOnNode = clusterConnection.keys(new RedisClusterNode("127.0.0.1", 7379, null), + Set keysOnNode = clusterConnection.keys(new RedisClusterNode("127.0.0.1", 7379, SlotRange.empty()), JedisConverters.toBytes("*")); assertThat(keysOnNode, hasItems(KEY_2_BYTES)); @@ -345,9 +346,9 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests { nativeConnection.set(KEY_1, VALUE_1); nativeConnection.set(KEY_2, VALUE_2); - assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7379, null)), is(1L)); - assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7380, null)), is(1L)); - assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7381, null)), is(0L)); + assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7379, SlotRange.empty())), is(1L)); + assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7380, SlotRange.empty())), is(1L)); + assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7381, SlotRange.empty())), is(0L)); } @Test // DATAREDIS-315 @@ -1653,7 +1654,7 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests { @Test // DATAREDIS-315 public void pingShouldRetrunPongForExistingNode() { - assertThat(clusterConnection.ping(new RedisClusterNode("127.0.0.1", 7379, null)), is("PONG")); + assertThat(clusterConnection.ping(new RedisClusterNode("127.0.0.1", 7379, SlotRange.empty())), is("PONG")); } @Test // DATAREDIS-315 @@ -1684,7 +1685,7 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests { nativeConnection.set(KEY_1, VALUE_1); nativeConnection.set(KEY_2, VALUE_2); - clusterConnection.flushDb(new RedisClusterNode("127.0.0.1", 7379, null)); + clusterConnection.flushDb(new RedisClusterNode("127.0.0.1", 7379, SlotRange.empty())); assertThat(nativeConnection.get(KEY_1), notNullValue()); assertThat(nativeConnection.get(KEY_2), nullValue()); diff --git a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionUnitTests.java b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionUnitTests.java index ec1c4ff3e..e66f2e7a5 100644 --- a/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/jedis/JedisClusterConnectionUnitTests.java @@ -45,6 +45,7 @@ import org.mockito.Spy; import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.stubbing.Answer; +import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.data.redis.ClusterStateFailureException; import org.springframework.data.redis.connection.ClusterInfo; import org.springframework.data.redis.connection.RedisClusterCommands.AddSlots; @@ -59,22 +60,16 @@ import org.springframework.data.redis.connection.jedis.JedisClusterConnection.Je public class JedisClusterConnectionUnitTests { private static final String CLUSTER_NODES_RESPONSE = "" // - + MASTER_NODE_1_ID + " " + CLUSTER_HOST + ":" + MASTER_NODE_1_PORT - + " myself,master - 0 0 1 connected 0-5460" - + "\n" + MASTER_NODE_2_ID + " " + CLUSTER_HOST + ":" - + MASTER_NODE_2_PORT - + " master - 0 1427718161587 2 connected 5461-10922" + "\n" - + MASTER_NODE_2_ID - + " " + CLUSTER_HOST + ":" + MASTER_NODE_3_PORT + " master - 0 1427718161587 3 connected 10923-16383"; + + MASTER_NODE_1_ID + " " + CLUSTER_HOST + ":" + MASTER_NODE_1_PORT + " myself,master - 0 0 1 connected 0-5460" + + "\n" + MASTER_NODE_2_ID + " " + CLUSTER_HOST + ":" + MASTER_NODE_2_PORT + + " master - 0 1427718161587 2 connected 5461-10922" + "\n" + MASTER_NODE_2_ID + " " + CLUSTER_HOST + ":" + + MASTER_NODE_3_PORT + " master - 0 1427718161587 3 connected 10923-16383"; - static final String CLUSTER_INFO_RESPONSE = "cluster_state:ok" + "\n" - + "cluster_slots_assigned:16384" + "\n" + "cluster_slots_ok:16384" - + "\n" + "cluster_slots_pfail:0" + "\n" - + "cluster_slots_fail:0" + "\n" + "cluster_known_nodes:4" - + "\n" + "cluster_size:3" + "\n" - + "cluster_current_epoch:30" + "\n" + "cluster_my_epoch:2" - + "\n" + "cluster_stats_messages_sent:2560260" - + "\n" + "cluster_stats_messages_received:2560086"; + static final String CLUSTER_INFO_RESPONSE = "cluster_state:ok" + "\n" + "cluster_slots_assigned:16384" + "\n" + + "cluster_slots_ok:16384" + "\n" + "cluster_slots_pfail:0" + "\n" + "cluster_slots_fail:0" + "\n" + + "cluster_known_nodes:4" + "\n" + "cluster_size:3" + "\n" + "cluster_current_epoch:30" + "\n" + + "cluster_my_epoch:2" + "\n" + "cluster_stats_messages_sent:2560260" + "\n" + + "cluster_stats_messages_received:2560086"; JedisClusterConnection connection; @@ -277,7 +272,7 @@ public class JedisClusterConnectionUnitTests { nodes.remove(CLUSTER_HOST + ":" + MASTER_NODE_3_PORT); - expectedException.expect(IllegalStateException.class); + expectedException.expect(DataAccessResourceFailureException.class); expectedException.expectMessage("Node " + CLUSTER_HOST + ":" + MASTER_NODE_3_PORT + " is unknown to cluster"); connection.serverCommands().dbSize(new RedisClusterNode(CLUSTER_HOST, MASTER_NODE_3_PORT)); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java index 7b375a1d8..6b4f09bc6 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClusterConnectionTests.java @@ -56,6 +56,7 @@ import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.DefaultSortParameters; import org.springframework.data.redis.connection.DefaultTuple; import org.springframework.data.redis.connection.RedisClusterNode; +import org.springframework.data.redis.connection.RedisClusterNode.SlotRange; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.connection.RedisListCommands.Position; import org.springframework.data.redis.connection.RedisNode; @@ -198,7 +199,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests { nativeConnection.set(KEY_1, VALUE_1); nativeConnection.set(KEY_2, VALUE_2); - Set keysOnNode = clusterConnection.keys(new RedisClusterNode("127.0.0.1", 7379, null), + Set keysOnNode = clusterConnection.keys(new RedisClusterNode("127.0.0.1", 7379, SlotRange.empty()), JedisConverters.toBytes("*")); assertThat(keysOnNode, hasItems(KEY_2_BYTES)); @@ -344,9 +345,9 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests { nativeConnection.set(KEY_1, VALUE_1); nativeConnection.set(KEY_2, VALUE_2); - assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7379, null)), is(1L)); - assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7380, null)), is(1L)); - assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7381, null)), is(0L)); + assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7379, SlotRange.empty())), is(1L)); + assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7380, SlotRange.empty())), is(1L)); + assertThat(clusterConnection.dbSize(new RedisClusterNode("127.0.0.1", 7381, SlotRange.empty())), is(0L)); } @Test // DATAREDIS-315 @@ -1658,7 +1659,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests { @Test // DATAREDIS-315 public void pingShouldRetrunPongForExistingNode() { - assertThat(clusterConnection.ping(new RedisClusterNode("127.0.0.1", 7379, null)), is("PONG")); + assertThat(clusterConnection.ping(new RedisClusterNode("127.0.0.1", 7379, SlotRange.empty())), is("PONG")); } @Test // DATAREDIS-315 @@ -1668,7 +1669,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests { @Test(expected = IllegalArgumentException.class) // DATAREDIS-315 public void pingShouldThrowExceptionWhenNodeNotKnownToCluster() { - clusterConnection.ping(new RedisClusterNode("127.0.0.1", 1234, null)); + clusterConnection.ping(new RedisClusterNode("127.0.0.1", 1234, SlotRange.empty())); } @Test // DATAREDIS-315 @@ -1689,7 +1690,7 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests { nativeConnection.set(KEY_1, VALUE_1); nativeConnection.set(KEY_2, VALUE_2); - clusterConnection.flushDb(new RedisClusterNode("127.0.0.1", 7379, null)); + clusterConnection.flushDb(new RedisClusterNode("127.0.0.1", 7379, SlotRange.empty())); assertThat(nativeConnection.get(KEY_1), notNullValue()); assertThat(nativeConnection.get(KEY_2), nullValue()); @@ -1733,7 +1734,8 @@ public class LettuceClusterConnectionTests implements ClusterConnectionTests { public void infoShouldCollectionInfoFromAllClusterNodes() { Properties singleNodeInfo = clusterConnection.serverCommands().info(new RedisClusterNode("127.0.0.1", 7380)); - assertThat(Double.valueOf(clusterConnection.serverCommands().info().size()), closeTo(singleNodeInfo.size() * 3, 12d)); + assertThat(Double.valueOf(clusterConnection.serverCommands().info().size()), + closeTo(singleNodeInfo.size() * 3, 12d)); } @Test // DATAREDIS-315 diff --git a/src/test/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListenerUnitTests.java b/src/test/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListenerUnitTests.java index 3e69023d8..28b8fe25f 100644 --- a/src/test/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListenerUnitTests.java +++ b/src/test/java/org/springframework/data/redis/listener/KeyExpirationEventMessageListenerUnitTests.java @@ -73,10 +73,10 @@ public class KeyExpirationEventMessageListenerUnitTests { verifyZeroInteractions(publisherMock); } - @Test // DATAREDIS-425 + @Test // DATAREDIS-425, DATAREDIS-692 public void handleMessageShouldNotRespondToEmptyMessage() { - listener.onMessage(new DefaultMessage(null, null), "*".getBytes()); + listener.onMessage(new DefaultMessage(new byte[] {}, new byte[] {}), "*".getBytes()); verifyZeroInteractions(publisherMock); }