The annotation processor scans @Command classes at compile time and generates wrapper classes. Each platform
(Standalone, Bukkit, Paper) has its own processor that extends BaseCommandProcessor to produce platform-specialized
wrapper code.
- Parse —
CommandParserreads@Command,@Default,@Resolve,@Name,@Greedy,@Suggest, and other annotations into a hierarchicalCommandModeltree (root command, nested subcommand classes, methods, and parameters). - Template Orchestration —
BaseCommandProcessor.buildWrapperClassruns a 6-step code generation pipeline. - Platform Specialization — Concrete platform processors (
StandaloneCommandProcessor,BukkitCommandProcessor,PaperCommandProcessor) override template hooks to configure platform interfaces, constructor arguments, entry methods, and helpers. - Generate — JavaPoet writes the wrapper
.javafile with explicit imports and clean syntax.
Step 1: configureClass() → Set class declaration, superclasses & BaseCommand interface
Step 2: addPlatformFields() → Declare command instance, manager, and platform-specific fields
Step 3: addConstructorStatements() → Constructor setup & nested subcommand instantiation
Step 4: generateEntryMethods() → Platform entry points (execute, tabComplete, or getCommandNode)
Step 5: generateHelpers() → Subcommand execution routing, suggestions, sender casting
Step 6: buildCommandInfo() → BaseCommand.getCommandInfo() metadata exposer
- Subcommand Dispatch: When arguments are provided,
switch (args[0].toLowerCase())matches subcommands and nested subcommand classes with O (1) jump table performance. - Minimum Argument Validation: Computes required parameter count at compile time and checks
if (args.length < required) throw new CommandException(...)before resolving parameters. - Parameter Resolution:
- Built-in types (primitives, strings, standard wrappers) use fast, inline
TypeSupportparsing. - Local
@Resolvemethods call the resolver method directly on the command instance. - Custom types invoke
manager.resolveParameter(...)via registeredArgumentResolvers.
- Built-in types (primitives, strings, standard wrappers) use fast, inline
- Dynamic Indexing: If a parameter uses a multi-width or dynamic resolver, the processor uses an
int[] argIdxHolder = { offset }to let resolvers consume variable numbers of arguments; otherwise, a simpleint argIdx = offsetis used. - SPI Validation: Runs
ParameterAnnotationHandler(e.g.@Min,@Max,@ValidateWith) andMethodAnnotationHandlerchecks.
- Tree Construction: Builds a native Brigadier tree (
LiteralArgumentBuilderandRequiredArgumentBuilder) at initialization time. - Execution Source: Parameters are resolved from the Brigadier context using
PaperExecutionSource(native Brigadier arguments ormanager.resolveParameter(...)).
| Component | Purpose |
|---|---|
CommandParser |
Reads annotations and builds CommandModel, MethodModel, and ParameterModel. |
BaseCommandProcessor |
Orchestrates code generation template, array execution routing, and suggestion helpers. |
TypeSupport |
Built-in type mappings for parsing, literals, and default suggestions. |
ResolverLookup |
Discovers local @Resolve methods and @Suggest providers in command classes. |
SpiLoader |
Discovers compile-time extensions (ParameterAnnotationHandler, MethodAnnotationHandler). |
SenderTypeRegistry |
Validates and tracks platform-specific sender types. |
Naming |
Generates deterministic, sanitized identifiers for generated fields and helper methods. |
Each @Command class produces a single wrapper class implementing BaseCommand:
| Platform | Suffix | Extends / Implements |
|---|---|---|
| Standalone | $StandaloneCommand |
implements StandaloneCommand (extends BaseCommand) |
| Bukkit | $BukkitCommand |
extends Command implements BaseCommand |
| Paper | $PaperCommand |
implements PaperCommand (extends BaseCommand) |
- All command execution and validation errors throw
CommandException. CommandManager.formatMessage(key, defaultFormat, args...)provides centralized, pluggable message formatting and localization (usage,unknown-subcommand,invalid-argument,missing-argument).