Argument providers are responsible for converting command input into specific types. Blade provides built-in providers for common types, but you can create custom providers for your own types.
ArgumentProvider Interface
The ArgumentProvider<T> interface is the core abstraction for argument parsing:
public interface ArgumentProvider<T> {
/**
* Converts the given InputArgument into the specific type.
*/
@Nullable
T provide(@NotNull Context ctx, @NotNull InputArgument arg) throws BladeParseError;
/**
* Suggests possible completions for the given InputArgument.
*/
default void suggest(@NotNull Context ctx,
@NotNull InputArgument arg,
@NotNull SuggestionsBuilder suggestions) throws BladeParseError {
}
/**
* Suggests possible completions with rich metadata (tooltips, etc.).
*/
default void suggestRich(@NotNull Context ctx,
@NotNull InputArgument arg,
@NotNull RichSuggestionsBuilder suggestions) throws BladeParseError {
suggest(ctx, arg, suggestions.legacyView());
}
}
Argument provider instances must be stateless, as a single instance will be used for all commands. If you do have to store some state, make sure to account for that.
Creating a Custom Provider
Here’s a complete example from the Blade README showing how to create a custom argument provider:
public class Data {
public String message;
public boolean wasProvided;
}
public class DataArgumentProvider implements ArgumentProvider<Data> {
@Override
public @Nullable Data provide(@NotNull Context ctx, @NotNull InputArgument arg) {
Data data = new Data();
if (arg.status() == InputArgument.Status.NOT_PRESENT) {
data.wasProvided = false;
data.message = "Default value: " + arg.value();
} else {
data.wasProvided = true;
data.message = arg.value();
}
return data;
}
@Override
public void suggest(@NotNull Context ctx, @NotNull InputArgument arg, @NotNull SuggestionsBuilder suggestions) {
suggestions.suggest("example");
}
}
Error Handling
When parsing fails, you can throw different types of errors:
// Show the command usage message
throw new BladeUsageMessage();
// Fail the command with a custom error message (non-recoverable)
throw BladeParseError.fatal("Custom error message");
// Allow recovery if the argument is optional
throw BladeParseError.recoverable("Custom error message");
The InputArgument class provides information about the argument:
public enum Status {
/**
* The argument was provided.
*/
PRESENT,
/**
* The argument was not provided.
*/
NOT_PRESENT
}
Check the status to handle optional arguments:
if (arg.status() == InputArgument.Status.NOT_PRESENT) {
// Handle missing argument
return defaultValue;
}
Advanced Provider Features
By default, providers are not called when the argument is null. Override this behavior:
@Override
public boolean handlesNullInputArguments() {
return true; // Provider will be called even with null arguments
}
This is useful for implementing logic for optional arguments, like handling @Opt.Type.SENDER.
Custom Default Argument Names
Provide a default name for arguments using this provider:
@Override
public @Nullable String defaultArgName(@NotNull AnnotatedElement element) {
return "player"; // Default name if @Name is not specified
}
Always Parse Quotes
Force quote parsing even without the @Quoted annotation:
@Override
public boolean alwaysParseQuotes() {
return true;
}
Registering Custom Providers
Register your custom provider in the Blade builder:
Blade.forPlatform(new BladeBukkitPlatform(this))
.bind(binder -> {
binder.bind(Data.class, new DataArgumentProvider());
})
.build();
Releasing Default Providers
You can remove built-in providers and replace them with your own:
.bind(binder -> {
binder.release(Player.class); // Remove the default provider
binder.bind(Player.class, new MyPlayerProvider()); // Add your own
})
Per-Parameter Providers
You can also specify a custom provider for individual parameters:
@Command("example")
public void example(
@Provider(MyPlayerProvider.class) Player customPlayer,
// Specify the scope (BOTH, PARSER, SUGGESTIONS)
@Provider(value = MyPlayerProvider.class, scope = Provider.Scope.SUGGESTIONS) Player customPlayer2
) {
// Command logic
}
Rich Suggestions
For Brigadier-based platforms, you can provide richer suggestions with tooltips:
@Override
public void suggestRich(@NotNull Context ctx,
@NotNull InputArgument arg,
@NotNull RichSuggestionsBuilder suggestions) throws BladeParseError {
suggestions.suggest("value1", "Tooltip for value1");
suggestions.suggest("value2", "Tooltip for value2");
}