Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RedisSetCommands.isMember(K key, Object... objects) throws ClassCastException #2759

Closed
ghost opened this issue Nov 1, 2023 · 5 comments
Closed
Assignees
Labels
status: invalid An issue that we don't feel is valid

Comments

@ghost
Copy link

ghost commented Nov 1, 2023

  • I use Java 17 , Redis Cluster version 7.0.10 and spring-data-redis 3.1.2
  • With the code that checks if a list of values ​​is in a set:
var member = stringRedisTemplate.opsForSet().isMember("Blacklist[115]", "eeq7OACuw81wCrxqPICIWg==", "test2");
  • I get this error:
java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Boolean (java.lang.Long and java.lang.Boolean are in module java.base of loader 'bootstrap')

	at org.springframework.data.redis.core.DefaultSetOperations.lambda$isMember$10(DefaultSetOperations.java:169)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:406)
	at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:373)
	at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:97)
	at org.springframework.data.redis.core.DefaultSetOperations.isMember(DefaultSetOperations.java:158)
	at com.elcom.ads.contactcacher.ContactCacherApplicationTests.contextLoads(ContactCacherApplicationTests.java:45)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
  • I reading source code and see error in line isMember.put(objects[i], result.get(i));
        // in class src/main/java/org/springframework/data/redis/core/DefaultSetOperations.java
	@Override
	public Map<Object, Boolean> isMember(K key, Object... objects) {

		byte[] rawKey = rawKey(key);
		byte[][] rawValues = rawValues(objects);

		return execute(connection -> {

			List<Boolean> result = connection.sMIsMember(rawKey, rawValues);

			if (result == null || result.size() != objects.length) {
				return null;
			}

			Map<Object, Boolean> isMember = new LinkedHashMap<>(result.size());

			for (int i = 0; i < objects.length; i++) {
				isMember.put(objects[i], result.get(i)); 
			}

			return isMember;
		});
	}
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 1, 2023
@jxblum jxblum changed the title The function isMember(K key, Object... objects) throws an exception ClassCastException isMember(K key, Object... objects) throws ClassCastException Nov 1, 2023
@jxblum jxblum changed the title isMember(K key, Object... objects) throws ClassCastException RedisSetCommands.isMember(K key, Object... objects) throws ClassCastException Nov 1, 2023
@jxblum
Copy link
Contributor

jxblum commented Nov 1, 2023

Could you please create a simple test case reproducing the issue?

Spring Data Redis already contains a test case for [Default]SetOperations.isMember(key, Object...) method; see here. This individual test case method tests for many different combinations of Redis driver [ Jedis, Lettuce ] combined with different types for keys and values; see here.

The difference between Redis standalone and cluster should not matter in this case.

I distilled this down into a more directed test case matching your setup; see here.

All tests pass with Jedis and Lettuce in Spring Data Redis 3.1.2 as well as in the latest 3.1 release: 3.1.5.

You cannot simply assume the result.get(i) invocation returns an numerical value simply because the Redis SMISMEMBER command (doc) returns 1 if the value is a member of the targeted set and 0 if not.

You have to consider the return value from the underlying Redis driver API (Jedis or Lettuce) used to invoke the set member command.

In the case of Jedis, Spring Data Redis calls Jedis::smismember, which is documented to return a List<Boolean>.

Even if you are indirectly calling the SD Redis JedisClusterSetCommands.sMIsMember(..) method, this in turn invokes the Jedis drivers JedisCluster.smismember(..) method, which again returns a List<Boolean>; see here.

In the case of Lettuce, Spring Data Redis simply calls Lettuce's RedisSetAsyncommands::smismember, which, of course, returns a List<Boolean> as documented.

NOTE: The RedisFuture<List<Boolean>> is properly handled and unwrapped by Spring Data Redis itself as a synchronous operations (i.e. waiting on the Future).

I wonder if you possibly altered your configuration in a non-prescribed, incompatible manner?

@jxblum jxblum self-assigned this Nov 1, 2023
@jxblum jxblum added status: waiting-for-feedback We need additional information before we can continue status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged labels Nov 1, 2023
@mp911de mp911de removed the status: invalid An issue that we don't feel is valid label Nov 2, 2023
@JohnZYP
Copy link

JohnZYP commented Nov 7, 2023

@thanbv1510 Please check if the Redisson dependency has been added. Remove it to resolve the issue, or alternatively, use Redisson's native API.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Nov 7, 2023
@ghost
Copy link
Author

ghost commented Nov 7, 2023

Yes, I using redisson with spring-data-redis, code correct if I remove redisson dependency

@jxblum jxblum added status: invalid An issue that we don't feel is valid and removed status: feedback-provided Feedback has been provided labels Nov 8, 2023
@jxblum
Copy link
Contributor

jxblum commented Nov 8, 2023

I can possibly see how Redisson might have caused this ClassCastException being on your Spring (Data) application classpath, particularly if it somehow involved (used) the referenced RedisCommand<List<Long>> object.

Of course, this was not apparent from the provided Stack Trace above.

In general, Spring Data Redis does not integrate with any other library, such as Redisson, only other Spring libs (e.g. Spring Data Commons, the core Spring Framework, etc) and the Redis drivers (Jedis and Lettuce) directly.

In particular, all integration of Redisson with Spring is handled by the Redisson project itself; see Features, toward the bottom of the list.

I will be closing this ticket as invalid for now.

@mrniko
Copy link

mrniko commented Oct 2, 2024

Fixed in redisson/redisson#6209

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

5 participants