11package org .evomaster .client .java .controller .redis ;
22
3- import org .evomaster .client .java .instrumentation .RedisCommand ;
4- import org .springframework .data .redis .connection .RedisConnectionFactory ;
5- import org .springframework .data .redis .core .RedisTemplate ;
6- import org .springframework .data .redis .serializer .StringRedisSerializer ;
7-
8- import java .util .Set ;
3+ import java .lang .reflect .Method ;
4+ import java .util .*;
95import java .util .stream .Collectors ;
106
7+ /**
8+ * RedisClient that uses Lettuce dynamically via reflection, avoiding
9+ * compile-time dependency on Spring or Lettuce.
10+ */
1111public class RedisClient {
1212
13- private final RedisTemplate <String , String > template ;
13+ private final Object redisClient ; // io.lettuce.core.RedisClient
14+ private final Object connection ; // io.lettuce.core.api.StatefulRedisConnection
15+ private final Object syncCommands ; // io.lettuce.core.api.sync.RedisCommands
16+
17+ public RedisClient (String host , int port ) {
18+ try {
19+ Class <?> redisClientClass = Class .forName ("io.lettuce.core.RedisClient" );
20+ Class <?> redisURIClass = Class .forName ("io.lettuce.core.RedisURI" );
21+
22+ Method createUri = redisURIClass .getMethod ("create" , String .class );
23+ Object uri = createUri .invoke (null , "redis://" + host + ":" + port );
24+
25+ Method createClient = redisClientClass .getMethod ("create" , redisURIClass );
26+ this .redisClient = createClient .invoke (null , uri );
27+
28+ Method connectMethod = redisClientClass .getMethod ("connect" );
29+ this .connection = connectMethod .invoke (redisClient );
30+
31+ Class <?> statefulConnClass = Class .forName ("io.lettuce.core.api.StatefulRedisConnection" );
32+ Method syncMethod = statefulConnClass .getMethod ("sync" );
33+ this .syncCommands = syncMethod .invoke (connection );
1434
15- public RedisClient (RedisConnectionFactory factory ) {
16- this .template = new RedisTemplate <>();
17- this .template .setConnectionFactory (factory );
18- StringRedisSerializer stringSerializer = new StringRedisSerializer ();
19- this .template .setKeySerializer (stringSerializer );
20- this .template .setValueSerializer (stringSerializer );
21- this .template .setHashKeySerializer (stringSerializer );
22- this .template .setHashValueSerializer (stringSerializer );
23- this .template .afterPropertiesSet ();
35+ } catch (Exception e ) {
36+ throw new RuntimeException ("Failed to initialize Lettuce Redis client via reflection" , e );
37+ }
2438 }
2539
26- public Set <String > getKeysByType (String expectedType ) {
27- return template .keys ("*" ).stream ().filter (
28- k -> template .type (k ).name ().equalsIgnoreCase (expectedType )
29- ).collect (Collectors .toSet ());
40+ public void close () {
41+ try {
42+ if (connection != null ) {
43+ Method close = connection .getClass ().getMethod ("close" );
44+ close .invoke (connection );
45+ }
46+ if (redisClient != null ) {
47+ Method shutdown = redisClient .getClass ().getMethod ("shutdown" );
48+ shutdown .invoke (redisClient );
49+ }
50+ } catch (Exception ignored ) {}
51+ }
52+
53+ /** Equivalent to SET key value */
54+ public void setValue (String key , String value ) {
55+ invoke ("set" , key , value );
56+ }
57+
58+ /** Equivalent to GET key */
59+ public String getValue (String key ) {
60+ return (String ) invoke ("get" , key );
3061 }
3162
63+ /** Equivalent to KEYS * */
3264 public Set <String > getAllKeys () {
33- return template .keys ("*" );
65+ Object result = invoke ("keys" , "*" );
66+ if (result instanceof Collection )
67+ return new HashSet <>((Collection <String >) result );
68+ return Collections .emptySet ();
3469 }
3570
36- public String getType (String key ){
37- return String .valueOf (template .type (key ));
71+ /** Equivalent to TYPE key */
72+ public String getType (String key ) {
73+ Object result = invoke ("type" , key );
74+ return result != null ? result .toString () : null ;
3875 }
3976
40- public Boolean hashFieldExists (String k , String targetField ){
41- return template .opsForHash ().hasKey (k , targetField );
77+ /** HSET key field value */
78+ public void hashSet (String key , String field , String value ) {
79+ invoke ("hset" , key , field , value );
4280 }
4381
44- public Set <String > getSetMembers (String key ){
45- return template .opsForSet ().members (key );
82+ /** HEXISTS key field */
83+ public boolean hashFieldExists (String key , String field ) {
84+ Object result = invoke ("hexists" , key , field );
85+ return result instanceof Boolean && (Boolean ) result ;
86+ }
87+
88+ /** SMEMBERS key */
89+ public Set <String > getSetMembers (String key ) {
90+ Object result = invoke ("smembers" , key );
91+ if (result instanceof Collection )
92+ return new HashSet <>((Collection <String >) result );
93+ return Collections .emptySet ();
94+ }
95+
96+ private Object invoke (String methodName , Object ... args ) {
97+ try {
98+ Class <?>[] argTypes = Arrays .stream (args )
99+ .map (Object ::getClass )
100+ .toArray (Class <?>[]::new );
101+
102+ Method method = findMethod (syncCommands .getClass (), methodName , argTypes );
103+ if (method == null )
104+ throw new RuntimeException ("Method not found: " + methodName );
105+ return method .invoke (syncCommands , args );
106+
107+ } catch (Exception e ) {
108+ throw new RuntimeException ("Error invoking Redis command: " + methodName , e );
109+ }
110+ }
111+
112+ private Method findMethod (Class <?> clazz , String name , Class <?>[] argTypes ) {
113+ for (Method m : clazz .getMethods ()) {
114+ if (!m .getName ().equals (name )) continue ;
115+ if (m .getParameterCount () != argTypes .length ) continue ;
116+ return m ;
117+ }
118+ return null ;
119+ }
120+
121+ public Set <String > getKeysByType (String expectedType ) {
122+ return getAllKeys ().stream ()
123+ .filter (k -> expectedType .equalsIgnoreCase (getType (k )))
124+ .collect (Collectors .toSet ());
46125 }
47126
48- public void setValue ( String key , String value ) {
49- template . opsForValue (). set ( key , value );
127+ public void flushAll () {
128+ invoke ( "flushall" );
50129 }
51130}
0 commit comments