spring-projects / spring-data-redis

Provides support to increase developer productivity in Java when using Redis, a key-value store. Uses familiar Spring concepts such as a template classes for core API usage and lightweight repository style data access.
https://spring.io/projects/spring-data-redis/
Apache License 2.0
1.77k stars 1.17k forks source link

RedisAtomicLong throws a null pointer if key is removed [DATAREDIS-469] #1048

Closed spring-projects-issues closed 8 years ago

spring-projects-issues commented 8 years ago

Walt Davidson opened DATAREDIS-469 and commented

RedisAtomicLong throws a null pointer on get, if the key has been removed/expired from the underlying Redis store. It looks like an autoboxing issue, when jedis returns null as the value for the key.

The code is quite clear. operations.get(key); returns null, and java unboxing to an int throws a NullPointer .

// In RedisAtomicLong:152
public long get() {
    return operations.get(key);
}

Stacktrace

java.lang.NullPointerException
    at org.springframework.data.redis.support.atomic.RedisAtomicLong.get(RedisAtomicLong.java:152)

Can be reproduced with a simple test

class RedisAtomicLongNullPointerTest extends GroovyTestCase {

    void testNewAtomicLong() {

        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(port: 6379, hostName: "127.0.0.1",usePool: false);
        jedisConnectionFactory.afterPropertiesSet();

        // setup long
        def test = new RedisAtomicLong("test",jedisConnectionFactory, 1)
        assertThat(test.get(), equalTo(1L))  // this passes

        // delete key
        new StringRedisTemplate(jedisConnectionFactory).delete("test")

        try {
            assertThat(test.get(), equalTo(0L))    
        } catch (NullPointerException npe) {
            fail("Unexpected Null Pointer");  // fails here
        }        
    }
}

Affects: 1.6.2 (Gosling SR2)

Referenced from: pull request https://github.com/spring-projects/spring-data-redis/pull/182

Backported to: 1.7.2 (Hopper SR2), 1.6.5 (Gosling SR5)

spring-projects-issues commented 8 years ago

Mark Paluch commented

We need to take also other operations into account. Incrementing absent keys leads in Redis to 1

127.0.0.1:6479> del key
(integer) 0
127.0.0.1:6479> incr key
(integer) 1

which seems ok to me to return 1. Decrementing works similar. The only operation which is not guarded is getAndSet. At this time the new value is already set and the command returns null