Skip to content

bug: ClassCastException when using AutoComplete with both withScore() and withPayload() options #673

@vovasalyha

Description

@vovasalyha

When using the autocomplete feature with both .withScore() and .withPayload() options enabled, a ClassCastException occurs. The application throws an error indicating that redis.clients.jedis.resps.Tuple cannot be cast to java.lang.String.

Steps to Reproduce (Example from the docs)

  1. Create an entity with @AutoComplete and @AutoCompletePayload annotations:
@Document
public class Airport {
  @Id
  private String id;

  @AutoComplete
  private String name;

  @AutoCompletePayload("name")  // Links to the "name" autocomplete field
  private String code;

  @AutoCompletePayload("name")
  private String city;

  @AutoCompletePayload("name")
  private String country;
}
  1. Use autocomplete with both score and payload options:
AutoCompleteOptions options = AutoCompleteOptions.get()
  .fuzzy()          // Enable fuzzy matching
  .withScore()      // Include relevance scores
  .withPayload()    // Include payload data
  .limit(10);       // Limit to 10 results

List<Suggestion> suggestions = airportRepository.autoCompleteName("john f k", options);

Expected Behavior

The autocomplete should return suggestions with both score and payload data.

Actual Behavior

The following exception is thrown:

java.lang.ClassCastException: class redis.clients.jedis.resps.Tuple cannot be cast to class java.lang.String
      at org.springframework.data.redis.serializer.StringRedisSerializer.serialize(StringRedisSerializer.java:36)
      at org.springframework.data.redis.core.AbstractOperations.rawHashKey(AbstractOperations.java:187)
      at org.springframework.data.redis.core.DefaultHashOperations.get(DefaultHashOperations.java:58)
      at com.redis.om.spring.ops.search.SearchOperationsImpl.lambda$getSuggestion$0(SearchOperationsImpl.java:138)

Root Cause Analysis

In SearchOperationsImpl.java, when both withScore() and withPayload() are enabled, the code receives suggestions as List<Tuple> objects. However, on line 138, it incorrectly passes the entire Tuple object as a hash key:

Object payload = template.opsForHash().get(payLoadKey, suggestion); // suggestion here is a Tuple, but opsForHash().get() expects a String key

The equivalent code path without scores (line 154) works because suggestion is already a String in that case.

Proposed Solution

The fix appears straightforward - extract the element from the Tuple before using it as a hash key:

Object payload = template.opsForHash().get(payLoadKey, suggestion.getElement());

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions