Skip to content

Hey there! If you like my work, you can support me by sponsoring me on GitHub. Thanks! ❤

Sponsor me
on GitHub

Jakarta

The litecommands-jakarta is a extension for supporting Jakarta EE annotation validation.
It allows you to use Jakarta EE Bean Validation annotations in the command arguments:

IMPORTANT

Make sure that you don't exclude META-INF from your project, jakarata doesn't work without it.


kotlin
implementation("dev.rollczi:litecommands-jakarta:3.9.1")
groovy
implementation "dev.rollczi:litecommands-jakarta:3.9.1"
xml
<dependency>
    <groupId>dev.rollczi</groupId>
    <artifactId>litecommands-jakarta</artifactId>
    <version>3.9.1</version>
</dependency>
Java
@Execute
void ban(@Arg @Size(min = 3, max = 16) String nick) {
    // Command implementation
}

Register Jakarta extension

Register the extension in the LiteCommands builder:

java
.extension(new LiteJakartaExtension<>(), config -> config
    // jakarta config ...
)
java
.extension(new LiteJakartaExtension<>())

Before configuration, it is worth knowing how the Jakarta Validation works in LiteCommands.

Suppose we have a command with a nick argument annotated with @Size and @Pattern annotations.

litecommands jakarta

1* - Argument nick (String)
2* - @Size jakarta annotation (between 3 and 16 characters)
3* - @Pattern jakarta annotation (only letters)
4* - Jakarta Validation (org.hibernate.validator:hibernate-validator implementation)
5* - Result of the validation (contains all violations)
6* - Constraint violations message (joined header with all violation messages)
7* - Violation message (specific message for each violation type)

See documentation for Jakarta EE Bean Validation to learn more about jakarta validation annotations.

Configure Jakarta messages

Constraint violations message

The .constraintViolationsMessage() method allows you to define a message for all constraint violations.

For example, we can define a message for all violations, which will contain the header and all violation messages. The result.asJoinedString() method joins all violation messages into one string.

Java
.constraintViolationsMessage((invocation, result) ->
    "[!] Custom constraint violations: \n" + result.asJoinedString("\n")
)

Result of the method will be:

Java
[!] Custom constraint violations:
<nick> - size must be between 3 and 16
<nick> - must match "[a-zA-Z]*"

Global violation message

The .violationMessage() method allows you to define a message for all violations.

For example, we can define a message for all violations, which will contain the parameter name and the violation message.

Java
.violationMessage((invocation, violation) ->
    " - " + violation.getParameterName() + ": " + violation.getMessage()
)

Result of the method will be:

Java
[!] Custom constraint violations:
 - nick: size must be between 3 and 16
 - nick: must match "[a-zA-Z]*"

Violation messages for specific annotations

The .violationMessage() method allows you to define a message for specific annotations.

For example, we can define a message for the @Size annotation.
The violation.getAnnotation() returns @Size annotation instance and allows you to get the annotation values.

Java
.violationMessage(Size.class, (invocation, violation) -> {
    Size size = violation.getAnnotation();
    int min = size.min();
    int max = size.max();
    String name = violation.getParameterName();

    return " - " + name + ": between " + min + " and " + max;
})

Result of the method will be:

Java
[!] Custom constraint violations:
 - nick: between 3 and 16
 - nick: must match "[a-zA-Z]*"

Violation messages for specific annotations in specific locale

First, we need to define how to get the locale for a command invocation.

Java
.locale(invocation -> {
    Locale locale = invocation.sender().getLocale();

    return locale != null ? locale : Locale.ENGLISH;
})

The .violationMessage() method allows you to define a message for specific annotations in specific locale.

For example, we can define a message for the @Pattern annotation in the English locale.

Java
.violationMessage(Pattern.class, (invocation, violation) -> {
    Pattern pattern = violation.getAnnotation();
    String name = violation.getParameterName();

    return Locale.ENGLISH.equals(violation.getLocale())
        ? " - " + name + ": [English] must match " + pattern.regexp()
        : " - " + name + ": [Polish] musi pasować do " + pattern.regexp();
})

Result for the English locale will be:

Java
[!] Custom constraint violations:
 - nick: [English] must match "[a-zA-Z]*"
 - nick: size must be between 3 and 16

Result for the other locale will be:

Java
[!] Custom constraint violations:
 - nick: [Polish] musi pasować do "[a-zA-Z]*"
 - nick: size must be between 3 and 16

Full configuration

Java
.extension(new LiteJakartaExtension<>(), config -> config
    // locale
    .locale(invocation -> {
        Locale locale = invocation.sender().getLocale();

        return locale != null ? locale : Locale.ENGLISH;
    })

    // constraint violations message
    .constraintViolationsMessage((invocation, result) ->
        "[!] Custom constraint violations: \n" + result.asJoinedString("\n")
    )

    // global violation message
    .violationMessage((invocation, violation) ->
        " - " + violation.getParameterName() + ": " + violation.getMessage()
    )

    // violation message for specific annotations
    .violationMessage(Size.class, (invocation, violation) -> {
        Size size = violation.getAnnotation();
        int min = size.min();
        int max = size.max();
        String name = violation.getParameterName();

        return " - " + name + ": between " + min + " and " + max;
    })

    .violationMessage(Pattern.class, (invocation, violation) -> {
        Pattern pattern = violation.getAnnotation();
        String name = violation.getParameterName();

        return Locale.ENGLISH.equals(violation.getLocale())
            ? " - " + name + ": [English] must match " + pattern.regexp()
            : " - " + name + ": [Polish] musi pasować do " + pattern.regexp();
    })
)

Advanced configuration

Custom validation factory

The .validationFactory() method allows you to define a custom validation factory.

For example, we can define a custom validation factory that will use the org.hibernate.validator:hibernate-validator implementation.

Java
.validationFactory(Validation.byProvider(HibernateValidator.class)
     .configure()
     // hibernate validator config ...
     .buildValidatorFactory()
)

Other examples

Java
@Command(name = "ban")
public class BanCommand {

    @Execute
    void ban(
        @Arg @Pattern(regexp = "[a-zA-Z_]+") String name,
        @Arg @Future Instant date
    ) {
        // Command implementation
    }

}
Java
@Command(name = "login")
public class LoginCommand {

    @Execute
    void login(@Arg @Size(min = 8) String password) {
        // Command implementation
    }

}
Java
@Command(name = "email")
public class EmailCommand {

    @Execute
    void email(@Arg @Email String email) {
        // Command implementation
    }

}
Java
@Command(name = "credit-card")

public class CreditCommand {

    @Execute
    void credit(@Arg @CreditCardNumber String cardNumber) {
        // Command implementation
    }

}

See also:

Made by LiteDevelopers and Contributors with ❤️