Skip to main content
Validation annotations and special-purpose annotations for advanced use cases.

Validation

@Range

Validates numeric parameters against minimum and maximum bounds.
min
double
default:"Double.NaN"
Minimum allowed value (inclusive). Use Double.NaN to leave unspecified.
max
double
default:"Double.NaN"
Maximum allowed value (inclusive). Use Double.NaN to leave unspecified.
@Command("setlevel")
public void setLevelCommand(
    @Sender Player player,
    @Name("level") @Range(min = 1, max = 100) int level
) {
    player.setLevel(level);
}
// Accepts: 1-100
// Rejects: 0, -1, 101

Error Messages

When validation fails, Blade sends an error message to the command sender:
The parameter 'level' must be between 1 and 100
You can customize error messages globally through the Blade builder:
Blade.forPlatform(plugin)
    .config(config -> config
        .invalidNumberError("Invalid number for '%s'")  
        .numberOutOfRangeError("'%s' must be between %s and %s")
    )
    .build();

Advanced Annotations

@Forwarded

Marks custom annotations to be forwarded to argument providers.
This is a meta-annotation (annotation for annotations) that enables type-safe parameter metadata.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@Forwarded
public @interface ItemCategory {
    String value();
}

public class ItemProvider implements ArgumentProvider<ItemStack> {
    @Override
    public ItemStack provide(Context context, Argument argument) {
        // Access the forwarded annotation
        ItemCategory category = argument.getParameter()
            .getAnnotation(ItemCategory.class);
        
        if (category != null) {
            return findItem(argument.getString(), category.value());
        }
        return findItem(argument.getString());
    }
}

@Command("give")
public void giveCommand(
    @Sender Player player,
    @Name("item") @ItemCategory("weapons") @Provider(ItemProvider.class) ItemStack item
) {
    player.getInventory().addItem(item);
}
Forwarded annotations are ignored by Blade’s parameter resolver and passed directly to the argument provider. This is cleaner than using @Data for structured metadata.

@EnumValue

Configures enum parsing behavior for the default enum argument provider.
name
String
default:""
Primary display name for the enum value. Defaults to the enum constant name.
aliases
String[]
default:"{}"
Additional accepted names for this enum value.
priority
int
default:"0"
Priority for resolving ambiguous matches. Higher values win.
hidden
boolean
default:"false"
Whether to hide this value from tab completion suggestions.
block
boolean
default:"false"
Whether to prevent this value from being used.
public enum GameMode {
    @EnumValue(name = "survival", aliases = {"s", "surv"})
    SURVIVAL,
    
    @EnumValue(name = "creative", aliases = {"c", "crea"})
    CREATIVE,
    
    @EnumValue(name = "adventure", aliases = {"a", "adv"})
    ADVENTURE,
    
    @EnumValue(name = "spectator", aliases = {"sp", "spec"}, hidden = true)
    SPECTATOR,
    
    @EnumValue(block = true)
    DEBUG  // Cannot be used
}

@Command("gamemode")
public void gamemodeCommand(
    @Sender Player player,
    @Name("mode") GameMode mode
) {
    player.setGameMode(convertMode(mode));
}
// Accepts: survival, s, surv, creative, c, etc.
// Tab completion shows: survival, creative, adventure (spectator hidden)
// Rejects: DEBUG
public enum ItemRarity {
    @EnumValue(name = "common", aliases = {"c"}, priority = 1)
    COMMON,
    
    @EnumValue(name = "uncommon", aliases = {"u", "c"}, priority = 2)
    UNCOMMON,
    
    @EnumValue(name = "rare", aliases = {"r"})
    RARE
}
// Input "c" matches both COMMON and UNCOMMON
// UNCOMMON wins due to higher priority

@HiddenEnumValue (Deprecated)

This annotation is deprecated. Use @EnumValue(hidden = true) or @EnumValue(block = true) instead.
Indicates an enum value should be hidden from suggestions.
block
boolean
default:"true"
Whether to block the usage of the enum value.
public enum GameMode {
    SURVIVAL,
    CREATIVE,
    ADVENTURE,
    
    @HiddenEnumValue
    SPECTATOR,
    
    @HiddenEnumValue(block = true)
    DEBUG
}
Migration to @EnumValue:
// Old
@HiddenEnumValue
SPECTATOR

// New
@EnumValue(hidden = true)
SPECTATOR

// Old
@HiddenEnumValue(block = true)
DEBUG

// New  
@EnumValue(block = true)
DEBUG

Error Handling

Validation Errors

Blade automatically handles validation errors and sends appropriate messages:
@Command("setlevel")
public void setLevel(@Name("level") @Range(min = 1, max = 100) int level) {}

// Input: /setlevel 150
// Output: The parameter 'level' must be between 1 and 100

Custom Validation

For complex validation, use custom argument providers:
public class PositiveIntProvider implements ArgumentProvider<Integer> {
    @Override
    public Integer provide(Context context, Argument argument) throws BladeExitMessage {
        int value = Integer.parseInt(argument.getString());
        
        if (value <= 0) {
            throw new BladeExitMessage("Value must be positive!");
        }
        
        return value;
    }
}

@Command("example")
public void example(
    @Name("value") @Provider(PositiveIntProvider.class) int value
) {
    // value is guaranteed to be positive
}

Combining Validations

You can combine multiple validation approaches:
@Command("transfer")
public void transferCommand(
    @Sender Player player,
    @Name("target") @Provider(OnlinePlayerProvider.class) Player target,
    @Name("amount") @Range(min = 1, max = 10000) int amount
) {
    // Both custom provider validation AND range validation
    if (player.equals(target)) {
        throw new BladeExitMessage("You cannot transfer to yourself!");
    }
    
    transferMoney(player, target, amount);
}

Build docs developers (and LLMs) love