Closed
Description
After upgrading to Jedis 6.0.0 while using Spring Data Redis 3.4.5, any call to StringRedisTemplate.opsForValue().set(...) (or equivalent) fails with:
java.lang.NoSuchMethodError: 'redis.clients.jedis.params.SetParams redis.clients.jedis.params.SetParams.ex(long)'
at org.springframework.data.redis.connection.jedis.JedisConverters.toSetCommandExPxArgument(JedisConverters.java:382)
at org.springframework.data.redis.connection.jedis.JedisStringCommands.set(JedisStringCommands.java:112)
at org.springframework.data.redis.connection.DefaultedRedisConnection.set(DefaultedRedisConnection.java:326)
at org.springframework.data.redis.core.DefaultValueOperations.lambda$set$15(DefaultValueOperations.java:208)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:411)
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:378)
at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:117)
at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:208)
at org.springframework.data.redis.core.ValueOperations.set(ValueOperations.java:75)
Spring Data Redis was compiled against a version of Jedis where SetParams declared its own public SetParams.ex(long) override. In Jedis PR #4095, that override was removed (inheriting the method from a now-package-private superclass), breaking binary compatibility.
Reproducability
Use spring-data-redis 3.4.5 in combination with Jedis 6.0.0
// build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.2'
id 'io.spring.dependency-management' version '1.1.0'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.data:spring-data-redis:3.4.5'
implementation 'redis.clients:jedis:6.0.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
//src/test/java/com/example/RedisReproducerTest.java
package com.example;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.time.Duration;
@SpringBootTest
class RedisReproducerTest {
@Autowired
private StringRedisTemplate redisTemplate;
@Test
void testSetWithExpiry() {
// This triggers the NoSuchMethodError at runtime
redisTemplate.opsForValue().set("test:key", "value", Duration.ofSeconds(10));
}
}
Expected behaviour
JedisConverters.toSetCommandExPxArgument
should be able to call SetParams.ex(long)
.
Either:
- Jedis 6.x re-introduces the public override SetParams.ex(long) in SetParams (i can create an issue there as well)
- Spring-data-redis updates its converter to call the inherited method reflectively or adapt to the new class hierarchy. (unlikely a good idea)
- Documentation is updated to note that Jedis 6.x is currently not binary-compatible and pinning to 5.x is required until spring-data-redis is compiled against the new Jedis version. (most pragmatic solution)