From 8b090dc364bd1685b07639b739e725f4b918f8e5 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 24 Mar 2016 09:19:42 +0100 Subject: [PATCH 1/3] DATAREDIS-469 - NPE in AtomicLong when key is removed. Prepare issue branch. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f50aae9fff..c1f1ef6628 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-redis - 1.7.0.BUILD-SNAPSHOT + 1.7.0.DATAREDIS-469-SNAPSHOT Spring Data Redis From bf8ee407ef60ee40e559737f9bdedbb3184bcfd6 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 24 Mar 2016 12:40:09 +0100 Subject: [PATCH 2/3] DATAREDIS-469 - Throw DataRetrievalFailureException for atomic numbers when key is removed. We now throw DataRetrievalFailureException in case of get() when the underlying key storing the value of an AtomicInteger, AtomicLong or AtomicDouble is removed from Redis. --- .../support/atomic/RedisAtomicDouble.java | 12 ++++++-- .../support/atomic/RedisAtomicInteger.java | 12 ++++++-- .../redis/support/atomic/RedisAtomicLong.java | 12 ++++++-- .../atomic/RedisAtomicDoubleTests.java | 28 ++++++++++++++++++- .../atomic/RedisAtomicIntegerTests.java | 28 ++++++++++++++++++- .../support/atomic/RedisAtomicLongTests.java | 26 +++++++++++++++++ 6 files changed, 110 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java index 992cd1eeb6..568475257b 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-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. @@ -20,6 +20,7 @@ import java.util.Date; import java.util.concurrent.TimeUnit; +import org.springframework.dao.DataRetrievalFailureException; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.BoundKeyOperations; @@ -38,6 +39,7 @@ * * @author Jennifer Hickey * @author Thomas Darimont + * @author Christoph Strobl */ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyOperations { @@ -143,7 +145,13 @@ private RedisAtomicDouble(String redisCounter, RedisOperations t * @return the current value */ public double get() { - return operations.get(key); + + Double value = operations.get(key); + if (value != null) { + return value.doubleValue(); + } + + throw new DataRetrievalFailureException(String.format("The key '%s' seems to no longer exist.", key)); } /** diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java index 224460aace..03c841e26c 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.util.Date; import java.util.concurrent.TimeUnit; +import org.springframework.dao.DataRetrievalFailureException; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.BoundKeyOperations; @@ -39,6 +40,7 @@ * @see java.util.concurrent.atomic.AtomicInteger * @author Costin Leau * @author Thomas Darimont + * @author Christoph Strobl */ public class RedisAtomicInteger extends Number implements Serializable, BoundKeyOperations { @@ -141,7 +143,13 @@ private RedisAtomicInteger(String redisCounter, RedisOperations * @return the current value */ public int get() { - return Integer.valueOf(operations.get(key)); + + Integer value = operations.get(key); + if (value != null) { + return value.intValue(); + } + + throw new DataRetrievalFailureException(String.format("The key '%s' seems to no longer exist.", key)); } /** diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java index a2e738f361..b3b54c54df 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2014 the original author or authors. + * Copyright 2011-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.util.Date; import java.util.concurrent.TimeUnit; +import org.springframework.dao.DataRetrievalFailureException; import org.springframework.data.redis.connection.DataType; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.BoundKeyOperations; @@ -39,6 +40,7 @@ * @see java.util.concurrent.atomic.AtomicLong * @author Costin Leau * @author Thomas Darimont + * @author Christoph Strobl */ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOperations { @@ -149,7 +151,13 @@ private RedisAtomicLong(String redisCounter, RedisOperations templ * @return the current value */ public long get() { - return operations.get(key); + + Long value = operations.get(key); + if (value != null) { + return value.longValue(); + } + + throw new DataRetrievalFailureException(String.format("The key '%s' seems to no longer exist.", key)); } /** diff --git a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicDoubleTests.java b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicDoubleTests.java index 09d1bf7cae..dd6c1fd727 100644 --- a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicDoubleTests.java +++ b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicDoubleTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-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. @@ -30,6 +30,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +import org.springframework.dao.DataRetrievalFailureException; import org.springframework.data.redis.ConnectionFactoryTracker; import org.springframework.data.redis.RedisTestProfileValueSource; import org.springframework.data.redis.connection.ConnectionUtils; @@ -44,6 +45,7 @@ * * @author Jennifer Hickey * @author Thomas Darimont + * @author Christoph Strobl */ @RunWith(Parameterized.class) public class RedisAtomicDoubleTests extends AbstractRedisAtomicsTests { @@ -210,4 +212,28 @@ public void testShouldBeAbleToUseRedisAtomicDoubleWithProperlyConfiguredRedisTem assertThat(ral.get(), is(32.23)); } + + /** + * @see DATAREDIS-469 + */ + @Test + public void getThrowsExceptionWhenKeyHasBeenRemoved() { + + expectedException.expect(DataRetrievalFailureException.class); + expectedException.expectMessage("'test' seems to no longer exist"); + + // setup long + RedisAtomicDouble test = new RedisAtomicDouble("test", factory, 1); + assertThat(test.get(), equalTo(1D)); // this passes + + RedisTemplate template = new RedisTemplate(); + template.setConnectionFactory(factory); + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(new GenericToStringSerializer(Long.class)); + template.afterPropertiesSet(); + + template.delete("test"); + + test.get(); + } } diff --git a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicIntegerTests.java b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicIntegerTests.java index bd28071ebf..400bff906d 100644 --- a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicIntegerTests.java +++ b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicIntegerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-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. @@ -30,6 +30,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +import org.springframework.dao.DataRetrievalFailureException; import org.springframework.data.redis.ConnectionFactoryTracker; import org.springframework.data.redis.connection.ConnectionUtils; import org.springframework.data.redis.connection.RedisConnection; @@ -44,6 +45,7 @@ * @author Costin Leau * @author Jennifer Hickey * @author Thomas Darimont + * @author Christoph Strobl */ @RunWith(Parameterized.class) public class RedisAtomicIntegerTests extends AbstractRedisAtomicsTests { @@ -180,4 +182,28 @@ public void testShouldBeAbleToUseRedisAtomicIntegerWithProperlyConfiguredRedisTe assertThat(ral.get(), is(32)); } + + /** + * @see DATAREDIS-469 + */ + @Test + public void getThrowsExceptionWhenKeyHasBeenRemoved() { + + expectedException.expect(DataRetrievalFailureException.class); + expectedException.expectMessage("'test' seems to no longer exist"); + + // setup long + RedisAtomicInteger test = new RedisAtomicInteger("test", factory, 1); + assertThat(test.get(), equalTo(1)); // this passes + + RedisTemplate template = new RedisTemplate(); + template.setConnectionFactory(factory); + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(new GenericToStringSerializer(Long.class)); + template.afterPropertiesSet(); + + template.delete("test"); + + test.get(); + } } diff --git a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicLongTests.java b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicLongTests.java index aeee29e86d..d19751c277 100644 --- a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicLongTests.java +++ b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicLongTests.java @@ -27,6 +27,7 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +import org.springframework.dao.DataRetrievalFailureException; import org.springframework.data.redis.ConnectionFactoryTracker; import org.springframework.data.redis.connection.ConnectionUtils; import org.springframework.data.redis.connection.RedisConnection; @@ -41,6 +42,7 @@ * @author Costin Leau * @author Jennifer Hickey * @author Thomas Darimont + * @author Christoph Strobl */ @RunWith(Parameterized.class) public class RedisAtomicLongTests extends AbstractRedisAtomicsTests { @@ -151,4 +153,28 @@ public void testShouldBeAbleToUseRedisAtomicLongWithProperlyConfiguredRedisTempl assertThat(ral.get(), is(32L)); } + + /** + * @see DATAREDIS-469 + */ + @Test + public void getThrowsExceptionWhenKeyHasBeenRemoved() { + + expectedException.expect(DataRetrievalFailureException.class); + expectedException.expectMessage("'test' seems to no longer exist"); + + // setup long + RedisAtomicLong test = new RedisAtomicLong("test", factory, 1); + assertThat(test.get(), equalTo(1L)); // this passes + + RedisTemplate template = new RedisTemplate(); + template.setConnectionFactory(factory); + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(new GenericToStringSerializer(Long.class)); + template.afterPropertiesSet(); + + template.delete("test"); + + test.get(); + } } From 07ae480f028b637fbfb9a3df2fdfeee15e7ba6b0 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 13 May 2016 14:34:21 +0200 Subject: [PATCH 3/3] DATAREDIS-469 - Polishing. Return zero (0) in getAndSet to prevent NullPointerExceptions. Remove trailing whitespace. Add tests for existing methods. Simplify tests. Original pull request: #182. --- .../support/atomic/RedisAtomicDouble.java | 41 ++++---- .../support/atomic/RedisAtomicInteger.java | 47 ++++++---- .../redis/support/atomic/RedisAtomicLong.java | 47 ++++++---- .../atomic/RedisAtomicDoubleTests.java | 44 +++++---- .../atomic/RedisAtomicIntegerTests.java | 93 +++++++++++++++---- .../support/atomic/RedisAtomicLongTests.java | 79 ++++++++++++++-- 6 files changed, 252 insertions(+), 99 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java index 568475257b..d47c758094 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicDouble.java @@ -36,10 +36,11 @@ /** * Atomic double backed by Redis. Uses Redis atomic increment/decrement and watch/multi/exec operations for CAS * operations. - * + * * @author Jennifer Hickey * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyOperations { @@ -51,7 +52,7 @@ public class RedisAtomicDouble extends Number implements Serializable, BoundKeyO /** * Constructs a new RedisAtomicDouble instance. Uses the value existing in Redis or 0 if none is found. - * + * * @param redisCounter redis counter * @param factory connection factory */ @@ -61,7 +62,7 @@ public RedisAtomicDouble(String redisCounter, RedisConnectionFactory factory) { /** * Constructs a new RedisAtomicDouble instance. - * + * * @param redisCounter * @param factory * @param initialValue @@ -96,7 +97,7 @@ private RedisAtomicDouble(String redisCounter, RedisConnectionFactory factory, D /** * Constructs a new RedisAtomicDouble instance. Uses the value existing in Redis or 0 if none is found. - * + * * @param redisCounter the redis counter * @param template the template * @see #RedisAtomicDouble(String, RedisConnectionFactory, double) @@ -110,7 +111,7 @@ public RedisAtomicDouble(String redisCounter, RedisOperations te * with appropriate {@link RedisSerializer} for the key and value. As an alternative one could use the * {@link #RedisAtomicDouble(String, RedisConnectionFactory, Double)} constructor which uses appropriate default * serializers. - * + * * @param redisCounter the redis counter * @param template the template * @param initialValue the initial value @@ -141,7 +142,7 @@ private RedisAtomicDouble(String redisCounter, RedisOperations t /** * Gets the current value. - * + * * @return the current value */ public double get() { @@ -156,7 +157,7 @@ public double get() { /** * Sets to the given value. - * + * * @param newValue the new value */ public void set(double newValue) { @@ -165,17 +166,23 @@ public void set(double newValue) { /** * Atomically sets to the given value and returns the old value. - * + * * @param newValue the new value * @return the previous value */ public double getAndSet(double newValue) { - return operations.getAndSet(key, newValue); + + Double value = operations.getAndSet(key, newValue); + if (value != null) { + return value.doubleValue(); + } + + return 0; } /** * Atomically sets the value to the given updated value if the current value {@code ==} the expected value. - * + * * @param expect the expected value * @param update the new value * @return true if successful. False return indicates that the actual value was not equal to the expected value. @@ -204,7 +211,7 @@ public Boolean execute(RedisOperations operations) { /** * Atomically increments by one the current value. - * + * * @return the previous value */ public double getAndIncrement() { @@ -213,7 +220,7 @@ public double getAndIncrement() { /** * Atomically decrements by one the current value. - * + * * @return the previous value */ public double getAndDecrement() { @@ -222,7 +229,7 @@ public double getAndDecrement() { /** * Atomically adds the given value to the current value. - * + * * @param delta the value to add * @return the previous value */ @@ -232,7 +239,7 @@ public double getAndAdd(final double delta) { /** * Atomically increments by one the current value. - * + * * @return the updated value */ public double incrementAndGet() { @@ -241,7 +248,7 @@ public double incrementAndGet() { /** * Atomically decrements by one the current value. - * + * * @return the updated value */ public double decrementAndGet() { @@ -250,7 +257,7 @@ public double decrementAndGet() { /** * Atomically adds the given value to the current value. - * + * * @param delta the value to add * @return the updated value */ @@ -260,7 +267,7 @@ public double addAndGet(double delta) { /** * Returns the String representation of the current value. - * + * * @return the String representation of the current value. */ public String toString() { diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java index 03c841e26c..a2e44270f6 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicInteger.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2016 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -36,11 +36,12 @@ /** * Atomic integer backed by Redis. Uses Redis atomic increment/decrement and watch/multi/exec operations for CAS * operations. - * + * * @see java.util.concurrent.atomic.AtomicInteger * @author Costin Leau * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ public class RedisAtomicInteger extends Number implements Serializable, BoundKeyOperations { @@ -52,7 +53,7 @@ public class RedisAtomicInteger extends Number implements Serializable, BoundKey /** * Constructs a new RedisAtomicInteger instance. Uses the value existing in Redis or 0 if none is found. - * + * * @param redisCounter redis counter * @param factory connection factory */ @@ -62,7 +63,7 @@ public RedisAtomicInteger(String redisCounter, RedisConnectionFactory factory) { /** * Constructs a new RedisAtomicInteger instance. - * + * * @param redisCounter the redis counter * @param factory the factory * @param initialValue the initial value @@ -73,7 +74,7 @@ public RedisAtomicInteger(String redisCounter, RedisConnectionFactory factory, i /** * Constructs a new RedisAtomicInteger instance. Uses the value existing in Redis or 0 if none is found. - * + * * @param redisCounter the redis counter * @param template the template * @see #RedisAtomicInteger(String, RedisConnectionFactory, int) @@ -87,7 +88,7 @@ public RedisAtomicInteger(String redisCounter, RedisOperations * with appropriate {@link RedisSerializer} for the key and value. As an alternative one could use the * {@link #RedisAtomicInteger(String, RedisConnectionFactory, Integer)} constructor which uses appropriate default * serializers. - * + * * @param redisCounter the redis counter * @param template the template * @param initialValue the initial value @@ -139,7 +140,7 @@ private RedisAtomicInteger(String redisCounter, RedisOperations /** * Get the current value. - * + * * @return the current value */ public int get() { @@ -154,7 +155,7 @@ public int get() { /** * Set to the given value. - * + * * @param newValue the new value */ public void set(int newValue) { @@ -163,17 +164,23 @@ public void set(int newValue) { /** * Set to the give value and return the old value. - * + * * @param newValue the new value * @return the previous value */ public int getAndSet(int newValue) { - return operations.getAndSet(key, newValue); + + Integer value = operations.getAndSet(key, newValue); + if (value != null) { + return value.intValue(); + } + + return 0; } /** * Atomically set the value to the given updated value if the current value == the expected value. - * + * * @param expect the expected value * @param update the new value * @return true if successful. False return indicates that the actual value was not equal to the expected value. @@ -202,7 +209,7 @@ public Boolean execute(RedisOperations operations) { /** * Atomically increment by one the current value. - * + * * @return the previous value */ public int getAndIncrement() { @@ -211,7 +218,7 @@ public int getAndIncrement() { /** * Atomically decrement by one the current value. - * + * * @return the previous value */ public int getAndDecrement() { @@ -220,7 +227,7 @@ public int getAndDecrement() { /** * Atomically add the given value to current value. - * + * * @param delta the value to add * @return the previous value */ @@ -230,7 +237,7 @@ public int getAndAdd(final int delta) { /** * Atomically increment by one the current value. - * + * * @return the updated value */ public int incrementAndGet() { @@ -239,7 +246,7 @@ public int incrementAndGet() { /** * Atomically decrement by one the current value. - * + * * @return the updated value */ public int decrementAndGet() { @@ -248,7 +255,7 @@ public int decrementAndGet() { /** * Atomically add the given value to current value. - * + * * @param delta the value to add * @return the updated value */ @@ -258,7 +265,7 @@ public int addAndGet(int delta) { /** * Returns the String representation of the current value. - * + * * @return the String representation of the current value. */ public String toString() { diff --git a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java index b3b54c54df..2f78d25a15 100644 --- a/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java +++ b/src/main/java/org/springframework/data/redis/support/atomic/RedisAtomicLong.java @@ -1,12 +1,12 @@ /* * Copyright 2011-2016 the original author or authors. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -36,11 +36,12 @@ /** * Atomic long backed by Redis. Uses Redis atomic increment/decrement and watch/multi/exec operations for CAS * operations. - * + * * @see java.util.concurrent.atomic.AtomicLong * @author Costin Leau * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOperations { @@ -52,7 +53,7 @@ public class RedisAtomicLong extends Number implements Serializable, BoundKeyOpe /** * Constructs a new RedisAtomicLong instance. Uses the value existing in Redis or 0 if none is found. - * + * * @param redisCounter redis counter * @param factory connection factory */ @@ -62,7 +63,7 @@ public RedisAtomicLong(String redisCounter, RedisConnectionFactory factory) { /** * Constructs a new RedisAtomicLong instance. - * + * * @param redisCounter * @param factory * @param initialValue @@ -97,7 +98,7 @@ private RedisAtomicLong(String redisCounter, RedisConnectionFactory factory, Lon /** * Constructs a new RedisAtomicLong instance. Uses the value existing in Redis or 0 if none is found. - * + * * @param redisCounter the redis counter * @param template the template * @see #RedisAtomicLong(String, RedisConnectionFactory, long) @@ -116,7 +117,7 @@ public RedisAtomicLong(String redisCounter, RedisOperations templa * As an alternative one could use the {@link #RedisAtomicLong(String, RedisConnectionFactory, Long)} constructor * which uses appropriate default serializers, in this case {@link StringRedisSerializer} for the key and * {@link GenericToStringSerializer} for the value. - * + * * @param redisCounter the redis counter * @param template the template * @param initialValue the initial value @@ -147,7 +148,7 @@ private RedisAtomicLong(String redisCounter, RedisOperations templ /** * Gets the current value. - * + * * @return the current value */ public long get() { @@ -162,7 +163,7 @@ public long get() { /** * Sets to the given value. - * + * * @param newValue the new value */ public void set(long newValue) { @@ -171,17 +172,23 @@ public void set(long newValue) { /** * Atomically sets to the given value and returns the old value. - * + * * @param newValue the new value * @return the previous value */ public long getAndSet(long newValue) { - return operations.getAndSet(key, newValue); + + Long value = operations.getAndSet(key, newValue); + if (value != null) { + return value.longValue(); + } + + return 0; } /** * Atomically sets the value to the given updated value if the current value {@code ==} the expected value. - * + * * @param expect the expected value * @param update the new value * @return true if successful. False return indicates that the actual value was not equal to the expected value. @@ -210,7 +217,7 @@ public Boolean execute(RedisOperations operations) { /** * Atomically increments by one the current value. - * + * * @return the previous value */ public long getAndIncrement() { @@ -219,7 +226,7 @@ public long getAndIncrement() { /** * Atomically decrements by one the current value. - * + * * @return the previous value */ public long getAndDecrement() { @@ -228,7 +235,7 @@ public long getAndDecrement() { /** * Atomically adds the given value to the current value. - * + * * @param delta the value to add * @return the previous value */ @@ -238,7 +245,7 @@ public long getAndAdd(final long delta) { /** * Atomically increments by one the current value. - * + * * @return the updated value */ public long incrementAndGet() { @@ -247,7 +254,7 @@ public long incrementAndGet() { /** * Atomically decrements by one the current value. - * + * * @return the updated value */ public long decrementAndGet() { @@ -256,7 +263,7 @@ public long decrementAndGet() { /** * Atomically adds the given value to the current value. - * + * * @param delta the value to add * @return the updated value */ @@ -266,7 +273,7 @@ public long addAndGet(long delta) { /** * Returns the String representation of the current value. - * + * * @return the String representation of the current value. */ public String toString() { diff --git a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicDoubleTests.java b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicDoubleTests.java index dd6c1fd727..b62e8d7eb8 100644 --- a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicDoubleTests.java +++ b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicDoubleTests.java @@ -42,21 +42,30 @@ /** * Integration test of {@link RedisAtomicDouble} - * + * * @author Jennifer Hickey * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ @RunWith(Parameterized.class) public class RedisAtomicDoubleTests extends AbstractRedisAtomicsTests { private RedisAtomicDouble doubleCounter; - private RedisConnectionFactory factory; + private RedisTemplate template; public RedisAtomicDoubleTests(RedisConnectionFactory factory) { - doubleCounter = new RedisAtomicDouble(getClass().getSimpleName() + ":double", factory); + + this.doubleCounter = new RedisAtomicDouble(getClass().getSimpleName() + ":double", factory); this.factory = factory; + + this.template = new RedisTemplate(); + this.template.setConnectionFactory(factory); + this.template.setKeySerializer(new StringRedisSerializer()); + this.template.setValueSerializer(new GenericToStringSerializer(Double.class)); + this.template.afterPropertiesSet(); + ConnectionFactoryTracker.add(factory); } @@ -201,12 +210,6 @@ public void testShouldThrowExceptionIfRedisAtomicDoubleIsUsedWithRedisTemplateAn @Test public void testShouldBeAbleToUseRedisAtomicDoubleWithProperlyConfiguredRedisTemplate() { - RedisTemplate template = new RedisTemplate(); - template.setConnectionFactory(factory); - template.setKeySerializer(new StringRedisSerializer()); - template.setValueSerializer(new GenericToStringSerializer(Double.class)); - template.afterPropertiesSet(); - RedisAtomicDouble ral = new RedisAtomicDouble("DATAREDIS-317.atomicDouble", template); ral.set(32.23); @@ -222,18 +225,27 @@ public void getThrowsExceptionWhenKeyHasBeenRemoved() { expectedException.expect(DataRetrievalFailureException.class); expectedException.expectMessage("'test' seems to no longer exist"); - // setup long + // setup double RedisAtomicDouble test = new RedisAtomicDouble("test", factory, 1); assertThat(test.get(), equalTo(1D)); // this passes - RedisTemplate template = new RedisTemplate(); - template.setConnectionFactory(factory); - template.setKeySerializer(new StringRedisSerializer()); - template.setValueSerializer(new GenericToStringSerializer(Long.class)); - template.afterPropertiesSet(); - template.delete("test"); test.get(); } + + /** + * @see DATAREDIS-469 + */ + @Test + public void getAndSetReturnsZeroWhenKeyHasBeenRemoved() { + + // setup double + RedisAtomicDouble test = new RedisAtomicDouble("test", factory, 1); + assertThat(test.get(), equalTo(1D)); // this passes + + template.delete("test"); + + assertThat(test.getAndSet(2), is(0D)); + } } diff --git a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicIntegerTests.java b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicIntegerTests.java index 400bff906d..1f7e3cff7d 100644 --- a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicIntegerTests.java +++ b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicIntegerTests.java @@ -41,21 +41,31 @@ /** * Integration test of {@link RedisAtomicInteger} - * + * * @author Costin Leau * @author Jennifer Hickey * @author Thomas Darimont * @author Christoph Strobl + * @author Mark Paluch */ @RunWith(Parameterized.class) public class RedisAtomicIntegerTests extends AbstractRedisAtomicsTests { private RedisAtomicInteger intCounter; private RedisConnectionFactory factory; + private RedisTemplate template; public RedisAtomicIntegerTests(RedisConnectionFactory factory) { - intCounter = new RedisAtomicInteger(getClass().getSimpleName() + ":int", factory); + + this.intCounter = new RedisAtomicInteger(getClass().getSimpleName() + ":int", factory); this.factory = factory; + + this.template = new RedisTemplate(); + this.template.setConnectionFactory(factory); + this.template.setKeySerializer(new StringRedisSerializer()); + this.template.setValueSerializer(new GenericToStringSerializer(Integer.class)); + this.template.afterPropertiesSet(); + ConnectionFactoryTracker.add(factory); } @@ -77,7 +87,7 @@ public static Collection testParams() { } @Test - public void testCheckAndSet() throws Exception { + public void testCheckAndSet() { // Txs not supported in Jredis assumeTrue(!ConnectionUtils.isJredis(factory)); intCounter.set(0); @@ -87,7 +97,7 @@ public void testCheckAndSet() throws Exception { } @Test - public void testIncrementAndGet() throws Exception { + public void testIncrementAndGet() { intCounter.set(0); assertEquals(1, intCounter.incrementAndGet()); } @@ -100,11 +110,55 @@ public void testAddAndGet() throws Exception { } @Test - public void testDecrementAndGet() throws Exception { + public void testDecrementAndGet() { intCounter.set(1); assertEquals(0, intCounter.decrementAndGet()); } + /** + * @see DATAREDIS-469 + */ + @Test + public void testGetAndIncrement() { + + intCounter.set(1); + assertEquals(1, intCounter.getAndIncrement()); + assertEquals(2, intCounter.get()); + } + + /** + * @see DATAREDIS-469 + */ + @Test + public void testGetAndAdd() { + + intCounter.set(1); + assertEquals(1, intCounter.getAndAdd(5)); + assertEquals(6, intCounter.get()); + } + + /** + * @see DATAREDIS-469 + */ + @Test + public void testGetAndDecrement() { + + intCounter.set(1); + assertEquals(1, intCounter.getAndDecrement()); + assertEquals(0, intCounter.get()); + } + + /** + * @see DATAREDIS-469 + */ + @Test + public void testGetAndSet() { + + intCounter.set(1); + assertEquals(1, intCounter.getAndSet(5)); + assertEquals(5, intCounter.get()); + } + @Test @Ignore("DATAREDIS-108 Test is intermittently failing") public void testCompareSet() throws Exception { @@ -171,12 +225,6 @@ public void testShouldThrowExceptionIfRedisAtomicIntegerIsUsedWithRedisTemplateA @Test public void testShouldBeAbleToUseRedisAtomicIntegerWithProperlyConfiguredRedisTemplate() { - RedisTemplate template = new RedisTemplate(); - template.setConnectionFactory(factory); - template.setKeySerializer(new StringRedisSerializer()); - template.setValueSerializer(new GenericToStringSerializer(Integer.class)); - template.afterPropertiesSet(); - RedisAtomicInteger ral = new RedisAtomicInteger("DATAREDIS-317.atomicInteger", template); ral.set(32); @@ -192,18 +240,27 @@ public void getThrowsExceptionWhenKeyHasBeenRemoved() { expectedException.expect(DataRetrievalFailureException.class); expectedException.expectMessage("'test' seems to no longer exist"); - // setup long + // setup integer RedisAtomicInteger test = new RedisAtomicInteger("test", factory, 1); assertThat(test.get(), equalTo(1)); // this passes - RedisTemplate template = new RedisTemplate(); - template.setConnectionFactory(factory); - template.setKeySerializer(new StringRedisSerializer()); - template.setValueSerializer(new GenericToStringSerializer(Long.class)); - template.afterPropertiesSet(); - template.delete("test"); test.get(); } + + /** + * @see DATAREDIS-469 + */ + @Test + public void getAndSetReturnsZeroWhenKeyHasBeenRemoved() { + + // setup integer + RedisAtomicInteger test = new RedisAtomicInteger("test", factory, 1); + assertThat(test.get(), equalTo(1)); // this passes + + template.delete("test"); + + assertThat(test.getAndSet(2), is(0)); + } } diff --git a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicLongTests.java b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicLongTests.java index d19751c277..685011b16a 100644 --- a/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicLongTests.java +++ b/src/test/java/org/springframework/data/redis/support/atomic/RedisAtomicLongTests.java @@ -38,7 +38,7 @@ /** * Integration test of {@link RedisAtomicLong} - * + * * @author Costin Leau * @author Jennifer Hickey * @author Thomas Darimont @@ -49,10 +49,19 @@ public class RedisAtomicLongTests extends AbstractRedisAtomicsTests { private RedisAtomicLong longCounter; private RedisConnectionFactory factory; + private RedisTemplate template; public RedisAtomicLongTests(RedisConnectionFactory factory) { - longCounter = new RedisAtomicLong(getClass().getSimpleName() + ":long", factory); + + this.longCounter = new RedisAtomicLong(getClass().getSimpleName() + ":long", factory); this.factory = factory; + + this.template = new RedisTemplate(); + this.template.setConnectionFactory(factory); + this.template.setKeySerializer(new StringRedisSerializer()); + this.template.setValueSerializer(new GenericToStringSerializer(Long.class)); + this.template.afterPropertiesSet(); + ConnectionFactoryTracker.add(factory); } @@ -102,8 +111,53 @@ public void testDecrementAndGet() throws Exception { assertEquals(0, longCounter.decrementAndGet()); } + /** + * @see DATAREDIS-469 + */ + @Test + public void testGetAndIncrement() { + + longCounter.set(1); + assertEquals(1, longCounter.getAndIncrement()); + assertEquals(2, longCounter.get()); + } + + /** + * @see DATAREDIS-469 + */ + @Test + public void testGetAndAdd() { + + longCounter.set(1); + assertEquals(1, longCounter.getAndAdd(5)); + assertEquals(6, longCounter.get()); + } + + /** + * @see DATAREDIS-469 + */ + @Test + public void testGetAndDecrement() { + + longCounter.set(1); + assertEquals(1, longCounter.getAndDecrement()); + assertEquals(0, longCounter.get()); + } + + /** + * @see DATAREDIS-469 + */ + @Test + public void testGetAndSet() { + + longCounter.set(1); + assertEquals(1, longCounter.getAndSet(5)); + assertEquals(5, longCounter.get()); + } + @Test public void testGetExistingValue() throws Exception { + longCounter.set(5); RedisAtomicLong keyCopy = new RedisAtomicLong(longCounter.getKey(), factory); assertEquals(longCounter.get(), keyCopy.get()); @@ -167,14 +221,23 @@ public void getThrowsExceptionWhenKeyHasBeenRemoved() { RedisAtomicLong test = new RedisAtomicLong("test", factory, 1); assertThat(test.get(), equalTo(1L)); // this passes - RedisTemplate template = new RedisTemplate(); - template.setConnectionFactory(factory); - template.setKeySerializer(new StringRedisSerializer()); - template.setValueSerializer(new GenericToStringSerializer(Long.class)); - template.afterPropertiesSet(); - template.delete("test"); test.get(); } + + /** + * @see DATAREDIS-469 + */ + @Test + public void getAndSetReturnsZeroWhenKeyHasBeenRemoved() { + + // setup long + RedisAtomicLong test = new RedisAtomicLong("test", factory, 1); + assertThat(test.get(), equalTo(1L)); // this passes + + template.delete("test"); + + assertThat(test.getAndSet(2), is(0L)); + } }