3636import io .lettuce .core .protocol .Command ;
3737import io .lettuce .core .protocol .CommandArgs ;
3838import io .lettuce .core .protocol .CommandType ;
39+ import io .lettuce .core .protocol .ProtocolKeyword ;
3940import io .lettuce .core .pubsub .StatefulRedisPubSubConnection ;
4041import io .lettuce .core .sentinel .api .StatefulRedisSentinelConnection ;
4142
4243import java .lang .reflect .Constructor ;
44+ import java .nio .charset .StandardCharsets ;
4345import java .util .ArrayList ;
4446import java .util .Collections ;
4547import java .util .HashMap ;
@@ -389,7 +391,7 @@ public Object execute(String command, @Nullable CommandOutput commandOutputTypeH
389391 Assert .hasText (command , "a valid command needs to be specified" );
390392
391393 String name = command .trim ().toUpperCase ();
392- CommandType commandType = CommandType . valueOf (name );
394+ ProtocolKeyword commandType = getCommandType (name );
393395
394396 validateCommandIfRunningInTransactionMode (commandType , args );
395397
@@ -1109,14 +1111,14 @@ io.lettuce.core.ScanCursor getScanCursor(long cursorId) {
11091111 return io .lettuce .core .ScanCursor .of (Long .toString (cursorId ));
11101112 }
11111113
1112- private void validateCommandIfRunningInTransactionMode (CommandType cmd , byte []... args ) {
1114+ private void validateCommandIfRunningInTransactionMode (ProtocolKeyword cmd , byte []... args ) {
11131115
11141116 if (this .isQueueing ()) {
11151117 validateCommand (cmd , args );
11161118 }
11171119 }
11181120
1119- private void validateCommand (CommandType cmd , @ Nullable byte []... args ) {
1121+ private void validateCommand (ProtocolKeyword cmd , @ Nullable byte []... args ) {
11201122
11211123 RedisCommand redisCommand = RedisCommand .failsafeCommandLookup (cmd .name ());
11221124 if (!RedisCommand .UNKNOWN .equals (redisCommand ) && redisCommand .requiresArguments ()) {
@@ -1128,6 +1130,15 @@ private void validateCommand(CommandType cmd, @Nullable byte[]... args) {
11281130 }
11291131 }
11301132
1133+ private static ProtocolKeyword getCommandType (String name ) {
1134+
1135+ try {
1136+ return CommandType .valueOf (name );
1137+ } catch (IllegalArgumentException e ) {
1138+ return new CustomCommandType (name );
1139+ }
1140+ }
1141+
11311142 /**
11321143 * {@link TypeHints} provide {@link CommandOutput} information for a given {@link CommandType}.
11331144 *
@@ -1136,7 +1147,7 @@ private void validateCommand(CommandType cmd, @Nullable byte[]... args) {
11361147 static class TypeHints {
11371148
11381149 @ SuppressWarnings ("rawtypes" ) //
1139- private static final Map <CommandType , Class <? extends CommandOutput >> COMMAND_OUTPUT_TYPE_MAPPING = new HashMap <>();
1150+ private static final Map <ProtocolKeyword , Class <? extends CommandOutput >> COMMAND_OUTPUT_TYPE_MAPPING = new HashMap <>();
11401151
11411152 @ SuppressWarnings ("rawtypes" ) //
11421153 private static final Map <Class <?>, Constructor <CommandOutput >> CONSTRUCTORS = new ConcurrentHashMap <>();
@@ -1298,7 +1309,7 @@ static class TypeHints {
12981309 * @return {@link ByteArrayOutput} as default when no matching {@link CommandOutput} available.
12991310 */
13001311 @ SuppressWarnings ("rawtypes" )
1301- public CommandOutput getTypeHint (CommandType type ) {
1312+ public CommandOutput getTypeHint (ProtocolKeyword type ) {
13021313 return getTypeHint (type , new ByteArrayOutput <>(CODEC ));
13031314 }
13041315
@@ -1309,7 +1320,7 @@ public CommandOutput getTypeHint(CommandType type) {
13091320 * @return
13101321 */
13111322 @ SuppressWarnings ("rawtypes" )
1312- public CommandOutput getTypeHint (CommandType type , CommandOutput defaultType ) {
1323+ public CommandOutput getTypeHint (ProtocolKeyword type , CommandOutput defaultType ) {
13131324
13141325 if (type == null || !COMMAND_OUTPUT_TYPE_MAPPING .containsKey (type )) {
13151326 return defaultType ;
@@ -1552,4 +1563,49 @@ public void onClose(StatefulConnection<?, ?> connection) {
15521563 connection .setAutoFlushCommands (true );
15531564 }
15541565 }
1566+
1567+ /**
1568+ * @since 2.3.8
1569+ */
1570+ static class CustomCommandType implements ProtocolKeyword {
1571+
1572+ private final String name ;
1573+
1574+ CustomCommandType (String name ) {
1575+ this .name = name ;
1576+ }
1577+
1578+ @ Override
1579+ public byte [] getBytes () {
1580+ return name .getBytes (StandardCharsets .US_ASCII );
1581+ }
1582+
1583+ @ Override
1584+ public String name () {
1585+ return name ;
1586+ }
1587+
1588+ @ Override
1589+ public boolean equals (Object o ) {
1590+
1591+ if (this == o ) {
1592+ return true ;
1593+ }
1594+ if (!(o instanceof CustomCommandType )) {
1595+ return false ;
1596+ }
1597+ CustomCommandType that = (CustomCommandType ) o ;
1598+ return ObjectUtils .nullSafeEquals (name , that .name );
1599+ }
1600+
1601+ @ Override
1602+ public int hashCode () {
1603+ return ObjectUtils .nullSafeHashCode (name );
1604+ }
1605+
1606+ @ Override
1607+ public String toString () {
1608+ return name ;
1609+ }
1610+ }
15551611}
0 commit comments