CommandObject.java
package redis.clients.jedis;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import redis.clients.jedis.annots.Experimental;
import redis.clients.jedis.args.Rawable;
public class CommandObject<T> {
private final CommandArguments arguments;
private final Builder<T> builder;
/**
* Hooks run against the {@link Connection} right before this command is sent, in list order, for
* per-connection setup that must precede it — HIMPORT injects a lazy {@code PREPARE} ahead
* of its {@code SET}, cluster ASK redirection appends an {@code ASKING} hook. Empty for ordinary
* commands. The command still travels the normal {@code CommandExecutor} path;
* {@link Connection#executeCommand(CommandObject)} invokes the hooks on the chosen connection,
* then sends the command as usual. Hooks are excluded from {@link #equals}/{@link #hashCode}: a
* hook-bearing copy is the same command.
*/
private final List<Consumer<Connection>> preProcessHooks;
public CommandObject(CommandArguments args, Builder<T> builder) {
this(args, builder, Collections.emptyList());
}
CommandObject(CommandArguments args, Builder<T> builder,
List<Consumer<Connection>> preProcessHooks) {
this.arguments = args;
this.builder = builder;
// Defensive copy so no caller-retained reference can mutate this command; empty stays
// allocation-free for ordinary commands.
this.preProcessHooks = preProcessHooks.isEmpty() ? Collections.emptyList()
: Collections.unmodifiableList(new ArrayList<>(preProcessHooks));
}
public CommandArguments getArguments() {
return arguments;
}
public Builder<T> getBuilder() {
return builder;
}
List<Consumer<Connection>> getPreProcessHooks() {
return preProcessHooks;
}
/**
* Returns a new command identical to this one with {@code hook} appended to its pre-process
* hooks; this instance is immutable and unaffected. Hooks run in append order on the connection
* right before the command is sent.
* @param hook per-connection setup to run just before this command
* @return a new {@code CommandObject} carrying the appended hook
* @since 8.0
*/
@Experimental
public CommandObject<T> withPreProcessHook(Consumer<Connection> hook) {
List<Consumer<Connection>> hooks = new ArrayList<>(preProcessHooks.size() + 1);
hooks.addAll(preProcessHooks);
hooks.add(hook);
return new CommandObject<>(arguments, builder, hooks);
}
@Override
public int hashCode() {
int hashCode = 1;
for (Rawable e : arguments) {
hashCode = 31 * hashCode + e.hashCode();
}
hashCode = 31 * hashCode + builder.hashCode();
return hashCode;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof CommandObject)) {
return false;
}
Iterator<Rawable> e1 = arguments.iterator();
Iterator<Rawable> e2 = ((CommandObject) o).arguments.iterator();
while (e1.hasNext() && e2.hasNext()) {
Rawable o1 = e1.next();
Rawable o2 = e2.next();
if (!(o1 == null ? o2 == null : o1.equals(o2))) {
return false;
}
}
if (e1.hasNext() || e2.hasNext()) {
return false;
}
return builder == ((CommandObject) o).builder;
}
}