Parameter Modifiers - adamtomi/grapefruit GitHub Wiki
Modifiers are basically annotations that influence the conversion process of each argument. Each parameter may have more modifiers. Basically, modifiers set certain requirements for parameters that have to be met, otherwise the mapping process will fail.
There are a couple of builtin modifiers:
Modifier | Required type | Description |
---|---|---|
@Greedy |
java.lang.String |
Joins all remaining strings into one string (the delimiter is a single whitespace). Only the last parameter can be annotated with this annotation. |
@Quotable |
java.lang.String |
Joins all string between double quotes (e.g.: "this is a quoted string") |
@Regex |
java.lang.String |
Tests the string against given regex and throws ParameterMappingException , if the test fails. |
@Flag |
ALL | Turns the argument into a flag argument. (Read more about them here) |
@Mapper |
ALL | Specifies which ParameterMapper should be used when converting the argument. |
@OptParam |
ALL | Turns the argument into an optional argument. |
@Range |
Any number type extending java.lang.Number and their primitive counterparts (if there is one) |
Determines a range. The value of the argument has to be between it's boundaries. |
@Source |
S (command source type)
|
Indicates that the value of the argument should be the source itself. Only the first parameter can be annotated with this annotation. |
Let's imagine that there is a class called User
. Each user may be a regular user or an admin, and we need to differentiate between the two. This is where modifiers shine!
First, create an annotation:
@Modifier
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface IsAdmin {}
Notice the @Modifier
annotation! Grapefruit need this to identify modifiers.
Now we need to check for @IsAdmin
:
public class UserMapper extends AbstractParamterMapper<CommandSource, User> {
private final UserManager userManager;
public UserMapper(final @NotNull UserManager userManager) {
super(TypeToken.of(User.class));
this.userManager = requireNonNull(userManager, "userManager cannot be null");
}
@Override
public @NotNull User map(final @NotNull CommandContext<CommandSource> context,
final @NotNull Queue<CommandInput> args,
final @NotNull AnnotationList modifiers) throws ParameterMappingException {
final String rawInput = args.element().rawArg();
final User user = this.userManager.findUser(rawInput).orElseThrow(() -> new ParameterMappingException(Message.of(
MyMessageKeys.USER_NOT_FOUND,
Template.of("{name}", rawInput))));
if (modifiers.has(IsAdmin.class) && !user.isAdmin()) {
throw new ParameterMappingException(Message.of(MyMessageKeys.USER_NOT_ADMIN, Template.of("{name}", rawInput)));
}
return user;
}
@Override
public @NotNull List<String> listSuggestions(final @NotNull CommandContext<CommandSource> context,
final @NotNull String currentArg,
final @NotNull AnnotationList modifiers) {
return this.userManager.getKnownUsers()
.stream()
.map(User::getName)
.toList();
}
}
The command may look something like this:
@CommandDefinition(route = "test")
public void onTestCommand(final User user, final @IsAdmin User admin) {}