A framework for JDA with everything you need to make a modern bot!
It supports Java 17+ and provides first-class Kotlin support, meaning you get full language support and a few extras!
Everything is built around it, it takes care of passing instances around, no need to instantiate classes, no passing everything everywhere.
It can also be replaced with Spring IoC.
Annotated and declarative application commands, with customizable argument processing, and smart automatic registration.
Example
@Command
class SlashBan {
@JDASlashCommand(name = "ban", description = "Bans an user")
suspend fun onSlashBan(
event: GuildSlashEvent,
@SlashOption(description = "The user to ban") user: User,
@SlashOption(description = "Timeframe of messages to delete") timeframe: Long,
// Use choices that come from the TimeUnit resolver
@SlashOption(description = "Unit of the timeframe", usePredefinedChoices = true) unit: TimeUnit, // A resolver is used here
@SlashOption(description = "Why the user gets banned") reason: String = "No reason supplied" // Optional
) {
// ...
event.reply_("${user.asMention} has been banned for '$reason'", ephemeral = true)
.deleteDelayed(5.seconds)
.await()
}
}Annotated and declarative application commands, with customizable argument processing or manual token consumption, supports prefix and mentions.
Example
@Command
class TextBan {
@JDATextCommandVariation(path = ["ban"], description = "Bans the mentioned user")
suspend fun onTextBan(
event: BaseCommandEvent,
@TextOption user: User,
@TextOption(example = "2") timeframe: Long,
@TextOption unit: TimeUnit, // A resolver is used here
@TextOption(example = "Get banned") reason: String = "No reason supplied" // Optional
) {
// ...
event.reply("${user.asMention} has been banned")
.deleteDelayed(5.seconds)
.await()
}
}Can then be used as @Bot ban @freya02 1 days A totally valid reason
Here's how the help content would look with a subcommand and a few more variations:
Database-backed components, can be used with callbacks, or bound to a method, optionally with passed data.
Similar API to components, can be used with callbacks, or bound to a method, optionally with passed data.
Custom (annotated) event handlers, with priorities and async.
Use powerful localization for your commands and replies.
- A PostgreSQL (and H2) database abstraction, with logged queries
- A smart event waiter with (multiple) preconditions, timeouts and consumers for every completion state
- Message parsers and emoji resolvers (turning
:joy:into π) - Paginators and menus of different types (using components!)
Amongst others!
You are strongly recommended to have some experience with Kotlin (or Java), OOP, JDA and Dependency Injection basics before you start using this library.
Head over to the wiki to get started.
After adding JDA:
<dependencies>
<dependency>
<groupId>io.github.freya022</groupId>
<artifactId>BotCommands</artifactId>
<version>VERSION</version>
</dependency>
</dependencies>repositories {
mavenCentral()
}
dependencies {
implementation("io.github.freya022:BotCommands:VERSION")
}To use the latest, unreleased changes, see SNAPSHOTS.md.
The base BotCommands artifact will include modules often used, while others are optional.
BotCommands-core: Root module which contains most features
BotCommands-jda-ktx: provides a set of Kotlin extensions and top-level functions, similar to jda-ktx.BotCommands-spring: Support for Spring BootBotCommands-typesafe-messages: Allows defining functions to retrieve text content from your bundles, providing better ergonomics and safety with load-time validationBotCommands-method-accessors-classfile: An alternative to reflective calls, leading to cleaner exceptions and faster callsBotCommands-restarter: Automatically restarts of your bot as your code changes
Here is how you would create a slash command that sends a message in a specified channel.
Kotlin
@Command
@RequiresComponents // (Optional) Disables the command if components are not enabled
class SlashSay(
private val buttons: Buttons // Factory for buttons
) {
// The descriptions can also be moved to localization files, reducing noise
@JDASlashCommand(name = "say", description = "Sends a message in a channel")
suspend fun onSlashSay(
event: GuildSlashEvent,
@SlashOption(description = "Channel to send the message in") channel: TextChannel,
@SlashOption(description = "What to say") content: String
) {
val deleteButton = buttons.danger(UnicodeEmojis.WASTEBASKET).ephemeral {
bindTo { buttonEvent ->
buttonEvent.deferEdit().queue()
buttonEvent.hook.deleteOriginal().await()
}
}
event.reply_("Done!", ephemeral = true)
.deleteDelayed(5.seconds)
.queue()
channel.sendMessage(content)
.addActionRow(deleteButton)
.await()
}
}Kotlin (DSL)
@Command
@RequiresComponents // (Optional) Disables the command if components are not enabled
class SlashSay(
private val buttons: Buttons // Factory for buttons
) : GlobalApplicationCommandProvider {
suspend fun onSlashSay(event: GuildSlashEvent, channel: TextChannel, content: String) {
val deleteButton = buttons.danger(UnicodeEmojis.WASTEBASKET).ephemeral {
bindTo { buttonEvent ->
buttonEvent.deferEdit().queue()
buttonEvent.hook.deleteOriginal().await()
}
}
event.reply_("Done!", ephemeral = true)
.deleteDelayed(5.seconds)
.queue()
channel.sendMessage(content)
.addActionRow(deleteButton)
.await()
}
// This is nice if you need to run your own code to declare commands.
// For example, a loop to create commands based on an enum
// If you don't need any dynamic stuff, just stick to annotations
override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
manager.slashCommand("say", function = ::onSlashSay) {
// The descriptions can also be moved to localization files
description = "Sends a message in a channel"
option("channel") {
description = "Channel to send the message in"
}
option("content") {
description = "What to say"
}
}
}
}Java
@Command
@RequiresComponents // (Optional) Disables the command if components are not enabled
public class SlashSay {
private final Buttons buttons; // Factory for buttons
public SlashSay(Buttons buttons) {
this.buttons = buttons;
}
// The descriptions can also be moved to localization files, reducing noise
@JDASlashCommand(name = "say", description = "Sends a message in a channel")
public void onSlashSay(
GuildSlashEvent event,
@SlashOption(description = "Channel to send the message in") TextChannel channel,
@SlashOption(description = "What to say") String content
) {
Button deleteButton = buttons.danger(UnicodeEmojis.WASTEBASKET).ephemeral()
.bindTo(buttonEvent -> {
buttonEvent.deferEdit().queue();
buttonEvent.getHook().deleteOriginal().queue();
})
.build();
event.reply("Done!")
.setEphemeral(true)
.delay(Duration.ofSeconds(5))
.flatMap(InteractionHook::deleteOriginal)
.queue();
channel.sendMessage(content)
.addActionRow(deleteButton)
.queue();
}
}IntelliJ IDEA users can use live templates provided in this zip file, helping you make commands and other handlers with predefined templates, for both Kotlin and Java, keeping a consistent naming scheme and acting as a cheatsheet.
For example, if you type slashCommand in your class, this will generate a slash command
and guide you through the declaration.
A list of live template can be found in Settings > Editor > Live Templates,
in the BotCommands 3.X - [Language] group.
For an installation guide, you can follow this guide from JetBrains.
Don't hesitate to join the support server if you have any question!
Due to the nature of JDA (and the Discord API), and to always improve the developer experience, the library could introduce breaking changes to allow quick adoption of newer features and better practices.
While attempting to reduce breaking changes by using deprecation mechanisms, it is not always possible or practical to use deprecations.
Small breaking/deprecating changes should be noticed via an increase of the minor version (3.0.Z -> 3.1.0),
while larger breaking changes should be seing an increase of the major version (3.Y.Z -> 4.0.0).
If you want to contribute, make sure to base your branch on 3.X, and create your PR from it.
It would be appreciated to focus on improving the documentation,
such as the wiki, the library documentation, or by creating examples.
Maintainers will focus on bug reports and feature requests, which you can create issues for.
Read the contributing guide for more details.

