1

I'm developing Spring Boot + Redis example. In this example, I've developed some custom methods which pull details based on RoleName. For the below method userRepository.findByRole_RoleName("ADMIN") or userRepository.findByMiddleNameContaining("Li");, we're getting the below exception.

The reference URL: https://docs.spring.io/spring-data/keyvalue/docs/1.2.15.RELEASE/reference/html/

Could anyone please provider pointers ? All the other methods are working fine. But just this method causing the problems. I will post all the required code below for reference.

Error:

java.lang.IllegalStateException: Failed to execute CommandLineRunner
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:795)
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:776)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1242)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1230)
    at com.baeldung.MainAppDemo.main(MainAppDemo.java:21)
Caused by: java.lang.IllegalArgumentException: CONTAINING (1): [IsContaining, Containing, Contains]is not supported for redis query derivation
    at org.springframework.data.redis.repository.query.RedisQueryCreator.from(RedisQueryCreator.java:67)
    at org.springframework.data.redis.repository.query.RedisQueryCreator.create(RedisQueryCreator.java:53)
    at org.springframework.data.redis.repository.query.RedisQueryCreator.create(RedisQueryCreator.java:41)
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createCriteria(AbstractQueryCreator.java:119)
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:95)
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:81)
    at org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.createQuery(KeyValuePartTreeQuery.java:211)
    at org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.prepareQuery(KeyValuePartTreeQuery.java:148)
    at org.springframework.data.keyvalue.repository.query.KeyValuePartTreeQuery.execute(KeyValuePartTreeQuery.java:106)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:602)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:590)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy65.findByMiddleNameContains(Unknown Source)
    at com.baeldung.MainAppDemo.run(MainAppDemo.java:38)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:792)
    ... 5 common frames omitted
2018-11-04 00:27:29,639 INFO  [main] org.springframework.context.support.AbstractApplicationContext: Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6f96c77: startup date [Sun Nov 04 00:27:26 IST 2018]; root of context hierarchy
2018-11-04 00:27:29,645 INFO  [main] org.springframework.jmx.export.MBeanExporter: Unregistering JMX-exposed beans on shutdown

User.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@RedisHash("user")
public class User {
    private @Id String id;
    private @Indexed String firstName;
    private @Indexed String middleName;
    private @Indexed String lastName;
    private Role role;
}

Role.java

@Data 
@Builder
@AllArgsConstructor
@NoArgsConstructor
@RedisHash("Role")
public class Role {
    private @Id String id;
    private @Indexed String roleName;
}

UserRepository.java

public interface UserRepository extends CrudRepository<User, String>{
    List<User> findByFirstNameAndLastName(String firstName, String lastName);

    List<User> findByMiddleNameContains(String firstName);

    List<User> findByRole_RoleName(String roleName);
}

MainAppDemo.java

@SpringBootApplication
public class MainAppDemo implements CommandLineRunner{

    @Autowired
    private UserRepository userRepository;

    public static void main(String[] args) {
        SpringApplication.run(MainAppDemo.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        Role role1 = Role.builder().id("R1").roleName("ADMIN").build();
        User user1 = User.builder().firstName("Matt").middleName("Mike").lastName("Wixson").role(role1).build();

        Role role2 = Role.builder().id("R2").roleName("API").build();
        User user2 = User.builder().firstName("John").middleName("Lima").lastName("Kerr").role(role2).build();

        userRepository.save(user1);
        userRepository.save(user2);

        List<User> u = userRepository.findByFirstNameAndLastName("Matt", "Wixson");
        System.out.println("Find By First Name and Last Name = "+u.toString());

        List<User> u2 = userRepository.findByMiddleNameContains("Li");
        System.out.println("Contains ="+u2);

        List<User> adminUser = userRepository.findByRole_RoleName("ADMIN");
        System.out.println("ADMIN USER ="+adminUser);
    }
}

JIRA defect: https://jira.spring.io/browse/DATAREDIS-887

UPDATE:

I developed the query like this and calling from the main method, still I am getting the same error. Please suggest working solution.

@Query("SELECT u FROM User u WHERE u.middleName LIKE :middleName ")
List<User> findByMiddleNameContaining(@Param("middleName") String middleName); 
Jeff Cook
  • 7,956
  • 36
  • 115
  • 186

2 Answers2

1

Ok lets start from "How Redis Work"

Redis work on Hashes for ID which helps in faster location of record. @Indexed is also hashed and stored for faster pin-pointing the record

So By Default for MiddleName the "contain" query will not work as Hash for "Test" string will not be contained in Hash for String "TestUser".

But ExampleMatcher is here to the rescue.

Source: https://docs.spring.io/spring-data/redis/docs/2.1.2.RELEASE/reference/html/#query-by-example

Solution for RoleName search on Role Object is relatively simple: Use this query

userRepository.findByRoleRoleName("ADMIN") (Basically remove the underscore)

And good news is that it can be combined with the above ExampleMatcher.

Let's discuss if you have doubt.

Helpfull Reference for RoleName search : Query Nested Objects in Redis using Spring Data

Vikas Saini
  • 444
  • 2
  • 11
0

On Redis with Spring Boot you just have some queries for finder that are supported like Is, Equals, combine with And, Or , you can take a look on Table 9:

https://docs.spring.io/spring-data/redis/docs/current/reference/html/#redis.repositories.queries

UPDATED

You can create a query following this documentation link as reference

https://docs.spring.io/spring-data/redis/docs/2.1.2.RELEASE/reference/html/#query-by-example

Jonathan JOhx
  • 5,784
  • 2
  • 17
  • 33
  • Is there any alternative solution over using Spring Data Redis? Like Jeddision or raddision which allows me to perform some complex queries? – Jeff Cook Nov 04 '18 at 05:49
  • You can create a custom query, here is there a reference https://stackoverflow.com/questions/42966967/creating-a-custom-query-with-spring-data-jpa – Jonathan JOhx Nov 04 '18 at 13:16
  • @ Jonathan Johx - Query annotation is purely part of the JPA. So Are you saying we should be using JPA API to talk to Redis in case to get data from Custom Query ? – Jeff Cook Nov 04 '18 at 13:53
  • @ Jonathan Johx - Please see UPDATE, I created Custom Query, still giving the same error. – Jeff Cook Nov 04 '18 at 14:02
  • Sorry, I was wrong the question xD hehe... I'm answering a lot the questions.. Really I'm sorry. – Jonathan JOhx Nov 04 '18 at 14:09
  • With Redis you can create queries using an Example, let me add the documentation.. https://docs.spring.io/spring-data/redis/docs/2.1.2.RELEASE/reference/html/#query-by-example – Jonathan JOhx Nov 04 '18 at 14:11
  • Redis doesn't seem mature enough to do custom query. I am really struggling to make this working with redis – Jeff Cook Nov 04 '18 at 14:12
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/183081/discussion-between-sayali-and-jonathan-johx). – Jeff Cook Nov 04 '18 at 14:13
  • Yes, I think that same, I got a couple of issues as you have them. – Jonathan JOhx Nov 04 '18 at 14:13