PaperMC Commands with Java and Brigadier
Reedwork lets you build PaperMC commands in Java using annotations instead of manually constructing Brigadier command nodes and registering every command component yourself.
Define your command structure with @Command and @SubCommand, implement execution with @CommandHandler, and let Reedwork map Java method parameters to the corresponding Paper command arguments.
The central idea is simple:
Your Java parameter types determine how command arguments are resolved.
This allows command handlers to work with typed Java values instead of raw command input.
Build a complete PaperMC command
Section titled “Build a complete PaperMC command”The following example defines a root command with a default handler, a player argument, and aliases:
package dev.reedworkmc.examples.command.commands;
import dev.reedworkmc.reedwork.annotation.Command;import dev.reedworkmc.reedwork.annotation.CommandHandler;import dev.reedworkmc.reedwork.annotation.SubCommand;import dev.reedworkmc.reedwork.command.CommandContext;import net.kyori.adventure.text.Component;import net.kyori.adventure.text.format.NamedTextColor;import org.bukkit.entity.Player;
@Command( value = "helloreedwork", description = "Send a welcome message to a player", permission = "reedwork.example.hello", cooldown = 10, aliases = {"hellorw", "hrw"})public final class HelloReedworkCommand {
private static final Component HELLO_MESSAGE = Component.text("Hello from Reedwork!", NamedTextColor.YELLOW);
@CommandHandler public boolean greetSelf(CommandContext context) { context.player().sendMessage(HELLO_MESSAGE); return true; }
@SubCommand("<target>") public boolean greetTarget(CommandContext context, Player target) { target.sendMessage(HELLO_MESSAGE);
context.player().sendMessage("Hello message sent to " + target.getName()); return true; }}From this class, Reedwork creates command paths equivalent to:
/helloreedwork/helloreedwork <target>/hellorw/hrwThe Player target parameter tells Reedwork that <target> should use a player argument.
You do not need to manually create the corresponding Brigadier argument node or convert the parsed value into a Player.
Reedwork handles that connection between the command declaration and the Java method.
How Reedwork commands work
Section titled “How Reedwork commands work”A Reedwork command consists of several cooperating parts:
| Part | Purpose |
|---|---|
@Command |
Declares the root command and its metadata. |
@SubCommand |
Defines additional command paths and arguments. |
@CommandHandler |
Defines the Java method executed for a command path. |
| Java parameter types | Determine how command arguments are parsed and resolved. |
@Suggest |
Adds custom command suggestions. |
Together, these declarations describe the command that Reedwork registers with Paper.
This keeps the command definition close to the Java code that implements its behavior.
Declare a Paper command
Section titled “Declare a Paper command”The @Command annotation defines the root command and its metadata.
| Attribute | Description |
|---|---|
value |
The command name. |
description |
Description associated with the command. |
permission |
Permission required to access the command. |
cooldown |
Command cooldown in seconds. |
aliases |
Alternative names for the command. |
usage |
Optional command usage string. |
For example:
@Command( value = "helloreedwork", description = "Send a welcome message to a player", permission = "reedwork.example.hello", cooldown = 10, aliases = {"hellorw", "hrw"}, usage = "/helloreedwork [target]")The @Command annotation defines the root of the command tree.
Execution paths are added through command handlers and subcommands.
Handle command execution
Section titled “Handle command execution”A method annotated with @CommandHandler defines an execution path.
@CommandHandlerpublic boolean greetSelf(CommandContext context) { context.player().sendMessage(HELLO_MESSAGE); return true;}For this handler, the corresponding command path is:
/helloreedworkA handler can receive a CommandContext, which provides information about the current command execution.
Returning true reports successful command execution.
A command can have a default handler while also exposing additional paths through subcommands.
Define command subcommands
Section titled “Define command subcommands”Additional command paths can be declared with @SubCommand.
@SubCommand("<target>")public boolean greetTarget(CommandContext context, Player target) { target.sendMessage(HELLO_MESSAGE);
context.player().sendMessage( "Hello message sent to " + target.getName() );
return true;}This creates the command path:
/helloreedwork <target>The value of @SubCommand describes the command structure relative to the root command.
Argument names and Java types
Section titled “Argument names and Java types”The text inside angle brackets defines the argument name shown by the command system:
<target>The argument name does not determine the Java type.
The Java method parameter does:
@SubCommand("<target>")public boolean greetTarget( CommandContext context, Player target) { // ...}Here, <target> is the command argument name and Player determines how Reedwork resolves its value.
This separation is important:
@SubCommanddefines the command structure and argument names.- The Java parameter type determines the argument resolver.
- Reedwork connects the command argument with the resolved Java value.
Multiple command arguments
Section titled “Multiple command arguments”A subcommand can contain multiple arguments and literal command components.
@SubCommand("give <player> <item> with <name> <amount>")public boolean give( CommandContext context, Player player, ItemStack item, String name, Integer amount) { // ...}This describes:
/give <player> <item> with <name> <amount>The literal with becomes part of the command path.
The Java parameters are mapped independently:
| Java parameter | Generated argument |
|---|---|
Player player |
Player argument |
ItemStack item |
Item Stack argument |
String name |
String argument |
Integer amount |
Integer argument |
This lets you describe structured Paper commands directly through Java method signatures.
Automatic Brigadier argument mapping
Section titled “Automatic Brigadier argument mapping”Automatic parameter mapping is one of Reedwork’s core features.
Java method parameters are mapped to the corresponding Paper command argument types.
For example:
@SubCommand("give <player> <item> with <name> <amount>")public boolean give( CommandContext context, Player player, ItemStack item, String name, Integer amount) { // ...}Reedwork uses the parameter types to determine how each argument should be parsed and resolved.
When the command executes, the handler receives the resulting Java values.
You do not need to manually:
- construct Brigadier argument nodes
- extract raw command arguments
- convert parsed values
- resolve supported player or entity arguments
- perform basic argument type validation
Reedwork handles the infrastructure between the command input and your Java method.
For more information about Paper’s available command argument types, see the Paper command argument documentation.
Supported parameter types
Section titled “Supported parameter types”Reedwork provides parameter resolvers for many of Paper’s Minecraft-specific Brigadier argument types.
The available resolvers currently include the following categories.
Primitive and value types
Section titled “Primitive and value types”| Java type | Paper argument | Description |
|---|---|---|
Boolean |
Boolean | Boolean values. |
Double |
Double | Decimal numbers. |
Float |
Float | Floating-point numbers. |
Integer |
Integer | Integer values. |
Long |
Long | Long integer values. |
String |
String | String command arguments. |
UUID |
UUID | UUID values. |
Bukkit and Paper types
Section titled “Bukkit and Paper types”| Java type | Paper argument | Description |
|---|---|---|
BlockState |
Block State | Resolves a block state. |
BlockPosition |
Block Position | Resolves a block position. |
Component |
Component | Resolves Adventure components. |
Criteria |
Objective Criteria | Resolves scoreboard objective criteria. |
DisplaySlot |
Scoreboard Display Slot | Resolves a scoreboard display slot. |
Entity |
Entity | Resolves an entity. |
FinePosition |
Fine Position | Resolves a precise world position. |
GameMode |
Game Mode | Resolves a Minecraft game mode. |
HexColor |
Hex Color | Resolves hexadecimal colors. |
HeightMap |
Height Map | Resolves a height map. |
ItemStack |
Item Stack | Resolves an item stack argument. |
ItemStackPredicate |
Item Predicate | Resolves an item predicate. |
Key |
Key | Resolves Adventure keys. |
LookAnchor |
Entity Anchor | Resolves an entity look anchor. |
NamedTextColor |
Named Color | Resolves Adventure named colors. |
NamespacedKey |
Namespaced Key | Resolves Bukkit namespaced keys. |
Player |
Player | Resolves a player. |
Style |
Style | Resolves Adventure text styles. |
World |
World | Resolves a world. |
Range types
Section titled “Range types”| Java type | Paper argument | Description |
|---|---|---|
DoubleRange |
Double Range | Resolves a double range. |
IntegerRange |
Integer Range | Resolves an integer range. |
Collection types
Section titled “Collection types”| Java type | Paper argument | Description |
|---|---|---|
List<Entity> |
Entities | Resolves multiple entities. |
List<Player> |
Players | Resolves multiple players. |
List<PlayerProfile> |
Player Profiles | Resolves multiple player profiles. |
Unsupported Paper argument types
Section titled “Unsupported Paper argument types”Some Paper argument types do not currently have a corresponding Reedwork resolver.
These include:
resource(RegistryKey)resourceKey(RegistryKey)signedMessage()time(int)templateMirror()templateRotation()
Reedwork’s resolver system is designed to map Paper command arguments to Java types where a corresponding representation is available.
Keeping unsupported types documented makes the resolver coverage explicit and helps developers determine whether a command can be represented directly through method parameters.
String arguments
Section titled “String arguments”String parameters receive special treatment based on their position in the command.
A String parameter followed by another command argument consumes a single argument.
For example:
/foo <name> <amount>with:
String name,Integer amountcreates a normal String argument for name.
Greedy string arguments
Section titled “Greedy string arguments”When a String parameter is the final argument of a command, Reedwork treats it as a greedy string.
For example:
/announce <message>with:
String messageallows message to consume the remaining command input.
This supports commands such as:
/announce Hello everyone, welcome to the server!without requiring you to manually select a greedy-string Brigadier argument.
This positional behavior allows structured command arguments and free-form text to be combined in the same command.
Custom command suggestions
Section titled “Custom command suggestions”Argument parsing and command suggestions are separate concerns.
The Java parameter type determines how the argument is parsed and resolved.
The @Suggest annotation determines which values are suggested to the player.
This allows Reedwork to combine automatic argument mapping with application-specific completion logic.
For example, a suggestion provider can read available values from an injected application service:
@Transientpublic final class PetSuggestionProvider implements SuggestionProvider<CommandSourceStack> {
private final PetIndex petIndex;
public PetSuggestionProvider(PetIndex petIndex) { this.petIndex = petIndex; }
@Override public CompletableFuture<Suggestions> getSuggestions( CommandContext<CommandSourceStack> context, SuggestionsBuilder builder ) { petIndex.getPetTypes() .forEach(builder::suggest);
return builder.buildFuture(); }}The provider can then be attached to a command parameter:
@SubCommand("<petType> <owner>")public boolean onCommand( CommandContext context, @Suggest(PetSuggestionProvider.class) String petType, Player owner) { handleCommand(context.sender(), petType, owner); return true;}The resulting command can be used as:
/pet <petType> <owner>petType remains a normal String argument while PetSuggestionProvider supplies custom suggestions.
The owner parameter is independently mapped to a Paper player argument because its Java type is Player.
This gives Reedwork three distinct layers:
| Layer | Responsibility |
|---|---|
@SubCommand |
Defines the command structure. |
| Java parameter type | Determines argument parsing and resolution. |
@Suggest |
Provides command completion suggestions. |
Suggestion providers can also use Reedwork’s dependency injection system, allowing application services to be injected without relying on global state.
Command permissions
Section titled “Command permissions”Commands can define a Bukkit/Paper permission directly through @Command.
@Command( value = "helloreedwork", permission = "reedwork.example.hello")The permission becomes part of the command’s access rules.
Command cooldowns
Section titled “Command cooldowns”A command can define a cooldown directly in its declaration.
@Command( value = "helloreedwork", cooldown = 10)The cooldown value is specified in seconds.
Reedwork handles the cooldown rather than requiring each command implementation to maintain its own cooldown state.
Command aliases
Section titled “Command aliases”Alternative command names can be declared with aliases.
@Command( value = "helloreedwork", aliases = {"hellorw", "hrw"})The command can then be invoked using:
/helloreedwork/hellorw/hrwAliases keep alternative command names in the command declaration instead of requiring separate registration logic.
Command usage
Section titled “Command usage”The usage attribute can be used to specify a custom usage string.
@Command( value = "helloreedwork", usage = "/helloreedwork [target]")Specifying usage is optional.
If usage is omitted, Reedwork automatically generates usage information from the available command paths and their arguments.
This means you normally do not need to maintain a separate usage string whenever the command structure changes.
Automatic command registration
Section titled “Automatic command registration”Reedwork removes the need to manually register each command with Bukkit or Paper.
The plugin initializes Reedwork and scans the package containing its components.
package dev.reedworkmc.examples.command;
import dev.reedworkmc.reedwork.Reedwork;import org.bukkit.plugin.java.JavaPlugin;
public final class CommandExample extends JavaPlugin {
@Override public void onEnable() { // Plugin startup logic Reedwork.create(this).scan("dev.reedworkmc.examples.command"); }}The scan call discovers the command and registers it automatically.
Adding another Reedwork command therefore does not require another explicit command registration step in the plugin’s main class.
Why use Reedwork for Paper commands?
Section titled “Why use Reedwork for Paper commands?”Traditional command implementations can require you to work directly with command nodes, argument types, parsing, suggestions, permissions, and registration.
Reedwork moves much of that infrastructure into annotations and Java method signatures.
A command class can describe:
- the command structure
- command metadata
- permissions
- aliases
- cooldowns
- usage
- argument types
- argument resolution
- custom suggestions
- execution handlers
Reedwork then connects that declaration to Paper’s command infrastructure.
You write the command behavior your plugin needs.
Reedwork handles the repetitive command infrastructure around it.
Commands and dependency injection
Section titled “Commands and dependency injection”Command handlers often depend on application services.
Instead of creating those services manually, Reedwork can resolve constructor dependencies automatically.
For example, a command can depend directly on a service:
public final class HelloCommand {
private final GreeterService greeterService;
public HelloCommand(GreeterService greeterService) { this.greeterService = greeterService; }}This keeps command dependencies explicit and makes larger Paper plugins easier to structure.
Learn more about dependency injection in Reedwork.
Next steps
Section titled “Next steps”Commands are only one part of the Reedwork framework.
Continue with the related documentation:
- Dependency injection — manage services and constructor dependencies.
- Events — automatically discover and register Bukkit and Paper event listeners.
- Enchantments — create and register custom Minecraft enchantments.
- Utilities — use reusable utilities for Paper plugin development.
If you are new to Reedwork, start with the introduction and then follow the installation guide.
The complete runnable command example is available in the ReedworkExamples repository.