Skip to content

Commit 2fdf928

Browse files
authored
COMMAND INFO reply contains subcommand detail (#4022)
* COMMAND INFO reply contains subcommand detail * Add 'name' in CommandInfo Fixes #4020 ___ * COMMAND INFO reply contains subcommand detail * Add 'name' in CommandInfo * Safeguard test from future ACL subcommands * Ensure reply size * Move null checking into COMMAND_INFO_BUILDER from inside loop and reduce parsing 'name' multiple times
1 parent 9b88636 commit 2fdf928

File tree

4 files changed

+83
-30
lines changed

4 files changed

+83
-30
lines changed

src/main/java/redis/clients/jedis/BuilderFactory.java

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -975,30 +975,8 @@ public Map<String, CommandDocument> build(Object data) {
975975
}
976976
};
977977

978-
public static final Builder<Map<String, CommandInfo>> COMMAND_INFO_RESPONSE = new Builder<Map<String, CommandInfo>>() {
979-
@Override
980-
public Map<String, CommandInfo> build(Object data) {
981-
if (data == null) {
982-
return null;
983-
}
984-
985-
List<Object> rawList = (List<Object>) data;
986-
Map<String, CommandInfo> map = new HashMap<>(rawList.size());
987-
988-
for (Object rawCommandInfo : rawList) {
989-
if (rawCommandInfo == null) {
990-
continue;
991-
}
992-
993-
List<Object> commandInfo = (List<Object>) rawCommandInfo;
994-
String name = STRING.build(commandInfo.get(0));
995-
CommandInfo info = CommandInfo.COMMAND_INFO_BUILDER.build(commandInfo);
996-
map.put(name, info);
997-
}
998-
999-
return map;
1000-
}
1001-
};
978+
@Deprecated
979+
public static final Builder<Map<String, CommandInfo>> COMMAND_INFO_RESPONSE = CommandInfo.COMMAND_INFO_RESPONSE;
1002980

1003981
public static final Builder<Map<String, LatencyLatestInfo>> LATENCY_LATEST_RESPONSE = new Builder<Map<String, LatencyLatestInfo>>() {
1004982
@Override

src/main/java/redis/clients/jedis/Jedis.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8250,7 +8250,7 @@ public List<KeyValue<String, List<String>>> commandGetKeysAndFlags(String... com
82508250
public Map<String, CommandInfo> commandInfo(String... commands) {
82518251
checkIsInMultiOrPipeline();
82528252
connection.sendCommand(COMMAND, joinParameters(Keyword.INFO.name(), commands));
8253-
return BuilderFactory.COMMAND_INFO_RESPONSE.build(connection.getOne());
8253+
return CommandInfo.COMMAND_INFO_RESPONSE.build(connection.getOne());
82548254
}
82558255

82568256
public List<String> commandList() {

src/main/java/redis/clients/jedis/resps/CommandInfo.java

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,40 @@
22

33
import redis.clients.jedis.Builder;
44

5+
import java.util.HashMap;
56
import java.util.List;
7+
import java.util.Map;
68

7-
import static redis.clients.jedis.BuilderFactory.STRING_LIST;
89
import static redis.clients.jedis.BuilderFactory.LONG;
10+
import static redis.clients.jedis.BuilderFactory.STRING;
11+
import static redis.clients.jedis.BuilderFactory.STRING_LIST;
912

1013
public class CommandInfo {
14+
15+
private final String name;
1116
private final long arity;
1217
private final List<String> flags;
1318
private final long firstKey;
1419
private final long lastKey;
1520
private final long step;
1621
private final List<String> aclCategories;
1722
private final List<String> tips;
18-
private final List<String> subcommands;
23+
private final Map<String, CommandInfo> subcommands;
1924

25+
/**
26+
* THIS IGNORES 'subcommands' parameter.
27+
* @param subcommands WILL BE IGNORED
28+
* @deprecated
29+
*/
30+
@Deprecated
2031
public CommandInfo(long arity, List<String> flags, long firstKey, long lastKey, long step,
2132
List<String> aclCategories, List<String> tips, List<String> subcommands) {
33+
this((String) null, arity, flags, firstKey, lastKey, step, aclCategories, tips, (Map) null);
34+
}
35+
36+
private CommandInfo(String name, long arity, List<String> flags, long firstKey, long lastKey, long step,
37+
List<String> aclCategories, List<String> tips, Map<String, CommandInfo> subcommands) {
38+
this.name = name;
2239
this.arity = arity;
2340
this.flags = flags;
2441
this.firstKey = firstKey;
@@ -29,6 +46,13 @@ public CommandInfo(long arity, List<String> flags, long firstKey, long lastKey,
2946
this.subcommands = subcommands;
3047
}
3148

49+
/**
50+
* Command name
51+
*/
52+
public String getName() {
53+
return name;
54+
}
55+
3256
/**
3357
* Arity is the number of arguments a command expects. It follows a simple pattern:
3458
* A positive integer means a fixed number of arguments.
@@ -89,25 +113,55 @@ public List<String> getTips() {
89113
/**
90114
* All the command's subcommands, if any
91115
*/
92-
public List<String> getSubcommands() {
116+
public Map<String, CommandInfo> getSubcommands() {
93117
return subcommands;
94118
}
95119

96120
public static final Builder<CommandInfo> COMMAND_INFO_BUILDER = new Builder<CommandInfo>() {
97121
@Override
98122
public CommandInfo build(Object data) {
123+
if (data == null) {
124+
return null;
125+
}
126+
99127
List<Object> commandData = (List<Object>) data;
128+
if (commandData.isEmpty()) {
129+
return null;
130+
}
100131

132+
String name = STRING.build(commandData.get(0));
101133
long arity = LONG.build(commandData.get(1));
102134
List<String> flags = STRING_LIST.build(commandData.get(2));
103135
long firstKey = LONG.build(commandData.get(3));
104136
long lastKey = LONG.build(commandData.get(4));
105137
long step = LONG.build(commandData.get(5));
106138
List<String> aclCategories = STRING_LIST.build(commandData.get(6));
107139
List<String> tips = STRING_LIST.build(commandData.get(7));
108-
List<String> subcommands = STRING_LIST.build(commandData.get(9));
140+
Map<String, CommandInfo> subcommands = COMMAND_INFO_RESPONSE.build(commandData.get(9));
141+
142+
return new CommandInfo(name, arity, flags, firstKey, lastKey, step, aclCategories, tips, subcommands);
143+
}
144+
};
109145

110-
return new CommandInfo(arity, flags, firstKey, lastKey, step, aclCategories, tips, subcommands);
146+
public static final Builder<Map<String, CommandInfo>> COMMAND_INFO_RESPONSE = new Builder<Map<String, CommandInfo>>() {
147+
@Override
148+
public Map<String, CommandInfo> build(Object data) {
149+
if (data == null) {
150+
return null;
151+
}
152+
153+
List<Object> rawList = (List<Object>) data;
154+
Map<String, CommandInfo> map = new HashMap<>(rawList.size());
155+
156+
for (Object rawCommandInfo : rawList) {
157+
CommandInfo info = CommandInfo.COMMAND_INFO_BUILDER.build(rawCommandInfo);
158+
if (info != null) {
159+
map.put(info.getName(), info);
160+
}
161+
}
162+
163+
return map;
111164
}
112165
};
166+
113167
}

src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,27 @@ public void commandInfo() {
520520
assertEquals(0, setInfo.getSubcommands().size());
521521
}
522522

523+
@Test // GitHub Issue #4020
524+
public void commandInfoAcl() {
525+
Map<String, CommandInfo> infos = jedis.commandInfo("ACL");
526+
assertThat(infos, Matchers.aMapWithSize(1));
527+
528+
CommandInfo aclInfo = infos.get("acl");
529+
assertEquals(-2, aclInfo.getArity());
530+
assertEquals(0, aclInfo.getFlags().size());
531+
assertEquals(0, aclInfo.getFirstKey());
532+
assertEquals(0, aclInfo.getLastKey());
533+
assertEquals(0, aclInfo.getStep());
534+
assertEquals(1, aclInfo.getAclCategories().size());
535+
assertEquals(0, aclInfo.getTips().size());
536+
assertThat(aclInfo.getSubcommands().size(), Matchers.greaterThanOrEqualTo(13));
537+
aclInfo.getSubcommands().forEach((name, subcommand) -> {
538+
assertThat(name, Matchers.startsWith("acl|"));
539+
assertNotNull(subcommand);
540+
assertEquals(name, subcommand.getName());
541+
});
542+
}
543+
523544
@Test
524545
public void commandList() {
525546
List<String> commands = jedis.commandList();

0 commit comments

Comments
 (0)