A solution to easily download dependencies at runtime with Gradle and my fork of Libby.
Firstly, in the settings.gradle file, add the plugin repository:
pluginManagement {
repositories {
maven { url = "https://jitpack.io" }
gradlePluginPortal()
}
}Then, simply apply the plugin in the build.gradle file:
plugins {
id 'com.github.MiguVerse.libby-gradle-plugin' version '1.3.0'
}Note: The legacy plugin ID xyz.miguvt.libby.plugin is also supported for backward compatibility, but using the JitPack ID is recommended for new projects.
(You can find the latest version in the releases)
Instead of using the compileOnly configuration, and then manually specifying the dependencies in the libby code, you
can simply replace compileOnly with libby:
dependencies {
libby 'com.zaxxer:HikariCP:5.0.1'
}When running the libby task (which will be automatically run when building) the plugin will create a libby.json file inside the final JAR. This file contains all the information about the dependencies (and their transient dependencies), and their repositories.
The plugin creates a libby.json manifest specifying what libraries should be loaded. How you use it depends on your platform:
If you're developing a Paper plugin, the gradle plugin can automatically generate a bootstrap loader that handles everything. Just ensure you have a paper-plugin.yml file and the loader will be auto-generated.
The generated loader:
- Downloads dependencies at bootstrap (before your plugin loads)
- Applies relocations using ASM bytecode transformation
- Caches downloaded and relocated JARs for fast subsequent loads
- Verifies checksums for security
No manual libby code required - the loader handles everything automatically.
For non-Paper platforms, you need to manually integrate libby in your plugin's onEnable():
BukkitLibraryManager libraryManager = new BukkitLibraryManager(this);
libraryManager.addMavenCentral();
// Automatically loads all libraries and relocations from libby.json
libraryManager.configureFromJSON();The configureFromJSON() method reads the libby.json file from your plugin's resources and automatically:
- Adds all configured repositories
- Downloads all libraries with checksum verification
- Applies all relocation rules
- Loads everything into your plugin's classpath
Relocation is an extremely important part when bundling libraries in plugins (or using libby). Fortunately for us, this can be simply achieved.
Firstly, we need to add the shadow plugin:
plugins {
id 'com.github.johnrengelman.shadow' version '8.1.1'
id 'com.github.MiguVerse.libby-gradle-plugin' version '1.3.0'
}Then, we need to add the relocation rules:
shadowJar {
relocate 'com.zaxxer.hikari', 'com.example.hikari'
}This will relocate all the classes in the com.zaxxer.hikari package to com.example.hikari. You can find more info
about relocation in
the shadow plugin documentation.
If you use the relocation feature, you must build your plugin using the shadowJar task!
The plugin automatically resolves all transient dependencies. While this is a useful feature, sometimes it downloads completely unnecessary dependencies.
For example, if you use the com.zaxxer:HikariCP:version dependency, it will
download org.slf4j:slf4j-api:version.
While this does make sense for a standalone application, plugin platforms like bukkit etc. already bundle in slf4j, so downloading it is not only unnecessary, but it can also cause conflicts.
Fortunately, this can be easily solved by excluding the dependency:
libby {
excludeDependency 'org.slf4j:.*:.*'
}So, what did we just do? The excludeDependency method takes a regular expression as an argument. This regular
expression is then compared against all dependencies ids (groupId:artifactId:version) and if it matches, the dependency
is
excluded from being downloaded by libby.
The plugin provides several configuration options to customize its behavior:
libby {
// Exclude dependencies using regex patterns (groupId:artifactId:version)
excludeDependency("org.slf4j:.*:.*")
excludeDependency("org.checkerframework:.*:.*")
excludeDependency("com.google.errorprone:.*:.*")
excludeDependency("com.google.protobuf:.*:.*")
// Disable checksum verification for dependencies that frequently redeploy
// the same version (causing false checksum mismatch flags)
noChecksumDependency("com.github.retrooper.packetevents:.*:.*")
// Paper plugin loader generation configuration
generatePaperLoader = false // set true to enable; null = auto-detect Paper projects
// loaderClassName = "GeneratedLibbyLoader" // customize the generated loader class name
// updatePaperPluginYml = true // set false to avoid modifying paper-plugin.yml
}Configuration Options:
-
excludeDependency(pattern): Excludes dependencies matching the regex pattern from being downloaded. Useful for platform-provided dependencies or unwanted transitive dependencies. -
noChecksumDependency(pattern): Disables checksum verification for dependencies matching the pattern. Use for libraries that frequently redeploy the same version number. -
generatePaperLoader: Controls automatic generation of Paper plugin loaders:true: Always generate Paper loaderfalse: Never generate Paper loadernull(default): Auto-detect Paper projects (looks forpaper-plugin.ymlor Paper plugin presence)
-
loaderClassName: Customizes the name of the generated Paper loader class (default: "GeneratedLibbyLoader") -
updatePaperPluginYml: Controls whether to automatically updatepaper-plugin.ymlwith the loader reference:true(default): Update the descriptor filefalse: Don't modify the descriptor file
If you use the Paper loader generator with relocation rules, you must include jar-relocator as a shaded dependency in your plugin. This is required because relocations are applied at bootstrap time before the plugin loads.
dependencies {
// Required for Paper loader with relocations
implementation 'me.lucko:jar-relocator:1.7'
}
shadowJar {
// Shade jar-relocator into your plugin (do NOT relocate it!)
// Your other relocations go here
relocate 'com.zaxxer.hikari', 'com.example.hikari'
}Important: Do NOT relocate me.lucko.jarrelocator - it must remain at its original package for the bootstrap loader to find it.
Note: If you don't have any relocations configured, jar-relocator is NOT required - the simple loader will be generated instead.
// build.gradle
plugins {
id 'java'
id 'com.gradleup.shadow' version '9.0.0-beta4'
id 'com.github.MiguVerse.libby-gradle-plugin' version '1.3.0'
}
group = 'com.example'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
compileOnly 'io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT'
// Runtime dependencies loaded by libby
libby 'com.zaxxer:HikariCP:5.1.0'
libby 'org.postgresql:postgresql:42.7.2'
// Required for relocations at bootstrap
implementation 'me.lucko:jar-relocator:1.7'
}
libby {
excludeDependency 'org.slf4j:.*:.*' // Paper provides SLF4J
}
shadowJar {
archiveClassifier.set('')
relocate 'com.zaxxer.hikari', 'com.example.libs.hikari'
relocate 'org.postgresql', 'com.example.libs.postgresql'
// Don't relocate jar-relocator!
}
build.dependsOn shadowJar# paper-plugin.yml
name: MyPlugin
version: '1.0.0'
main: com.example.MyPlugin
api-version: '1.21'
# loader will be auto-added by the pluginThat's it! The plugin will:
- Generate
libby.jsonwith your dependencies - Generate
GeneratedLibbyLoader.javain your source folder - Update
paper-plugin.ymlwith the loader reference - At runtime, download, relocate, and load dependencies before your plugin starts