Custom Command Arguments
CommandArguments is the object passed to command and completer methods. By default, the framework creates the built-in class for every execution, but you can now provide your own subclass and make every command receive richer helper methods.
This is useful when you repeatedly write the same validation, formatting, player lookup, or plugin-specific utility code inside commands.
Creating a Custom Arguments Class
Section titled “Creating a Custom Arguments Class”The simplest approach is to extend CommandArguments and expose a copy constructor.
public class PluginArguments extends CommandArguments {
public PluginArguments(CommandArguments arguments) { super(arguments); }
public Player requirePlayer() { if (!isSenderPlayer()) { sendMessage("<red>This command can only be used by players."); throw new IllegalStateException("Sender is not a player."); }
return getSender(); }
public void success(String message) { sendMessage("<green>" + message); }
public void error(String message) { sendMessage("<red>" + message); }}The copy constructor receives the framework-created CommandArguments instance and passes its internal sender, command, label, and argument array to the parent constructor.
Registering the Default Arguments Class
Section titled “Registering the Default Arguments Class”Use setDefaultArguments(Class) when your custom class has either a copy constructor or the full constructor signature.
public class Main extends JavaPlugin {
private CommandFramework commandFramework;
@Override public void onEnable() { commandFramework = new CommandFramework(this);
// Must be configured before command registration. commandFramework.setDefaultArguments(PluginArguments.class);
commandFramework.registerCommands(this); }
@Command(name = "profile", senderType = Command.SenderType.PLAYER) public void profileCommand(PluginArguments arguments) { Player player = arguments.requirePlayer(); arguments.success("Opening profile for " + player.getName() + "."); }}After this setup, command methods can request PluginArguments directly. You do not need to cast the base CommandArguments object manually.
Using a Factory
Section titled “Using a Factory”If your custom arguments object needs dependencies, use the factory overload instead of reflection.
public class Main extends JavaPlugin {
private Economy economy;
@Override public void onEnable() { CommandFramework commandFramework = new CommandFramework(this);
commandFramework.setDefaultArguments(arguments -> new EconomyArguments(arguments, economy) );
commandFramework.registerCommands(this); }}public class EconomyArguments extends CommandArguments {
private final Economy economy;
public EconomyArguments(CommandArguments arguments, Economy economy) { super(arguments); this.economy = economy; }
public double getBalance() { return economy.getBalance(getSender().getName()); }}The factory receives the base CommandArguments for the current command execution and must return a non-null subclass instance.
Constructor Options
Section titled “Constructor Options”The class-based overload supports two constructor styles.
public PluginArguments(CommandArguments arguments) { super(arguments);}public PluginArguments( CommandSender sender, org.bukkit.command.Command bukkitCommand, dev.despical.commandframework.annotations.Command command, String label, String[] arguments) { super(sender, bukkitCommand, command, label, arguments);}If neither constructor exists, the framework throws an IllegalArgumentException while configuring the default arguments class.
Using Custom Arguments in Completers
Section titled “Using Custom Arguments in Completers”The same default arguments configuration is also used for tab completers.
@Completer(name = "warp")public List<String> warpCompletion(PluginArguments arguments) { if (!arguments.hasPermission("example.warp")) { return List.of(); }
return List.of("spawn", "market", "arena");}This lets you share the same permission helpers, lookup methods, and formatting shortcuts across command execution and completion code.
Best Practices
Section titled “Best Practices”Keep custom arguments focused on command-context utilities.
Good examples include:
- sender helpers
- common permission checks
- message formatting shortcuts
- player or plugin service lookups
- argument validation helpers
Avoid placing long command workflows inside the arguments class. Command behavior is usually easier to maintain inside the command method or a dedicated service.