Tags
Creators
Details
3.53.0.0+2026-04-14
Compatibility
Changes
api: child-first classloader workaround in MinecraftSqliteJdbc
Bukkit/Spigot/Paper bundle sqlite-jdbc on the server's parent classloader. Plugin classloaders delegate parent-first, so any consumer plugin that does Class.forName("org.sqlite.JDBC") or DriverManager.getConnection always resolves to the bundled driver — installing this holder mod has no effect under default semantics, regardless of what's in plugins/.
Verified empirically across paper-1.12.2 (engine 3.21.0 bundled) and paper-1.21.11 (engine 3.49.1.0 in libraries/) — the holder loads as a plugin but its driver class is never consulted, DriverManager registers only the bundled driver, sqlite_version() returns the bundled engine.
This commit adds a public API class that gives consumers an explicit escape hatch: a child-first URLClassLoader pointing at this holder's own jar, parented to the platform classloader so org.sqlite.* must come from the holder jar (the parent chain has no org.sqlite). The Driver loaded from this classloader has a distinct class identity from the bundled copy, so DriverManager.getConnection still hits bundled but MinecraftSqliteJdbc.connect() returns a connection through the holder's engine.
Verified on paper-1.12.2 in the same JVM: baseline DriverManager → engine 3.21.0 child-first holder API → engine 3.53.0
API surface: Connection connect(String url) Connection connect(String url, Properties properties) Driver driver() String engineVersion() String driverVersion() void eagerInit() void shutdown()
Caveats are documented in the class javadoc — chiefly: stick to java.sql.* interfaces (the impl class org.sqlite.SQLiteConnection lives in the child-first classloader and won't down-cast across boundaries), DriverManager.getConnection won't pick this driver up (use connect() directly), and the native SQLite library is extracted twice when both bundled and holder are in use (one extraction per classloader).
DEFAULT PATH IS UNCHANGED
Consumer plugins that don't need a newer engine continue to use DriverManager.getConnection like always — they pick up the bundled driver and don't need to softdepend on this holder. Install this holder only on Fabric/NeoForge (no bundled driver) or when you specifically want a newer SQLite engine than what your server bundles.
INTEGRATION
Grim's SqliteBackend wires this in: probes for MinecraftSqliteJdbc at init, compares engineVersion() to the bundled, routes through the holder when it's strictly newer. Lets a Paper 1.8-1.12 server use modern UPSERT writers (which need engine 3.24+) by installing this mod.
Implementation moved to a separate :api Gradle subproject with Java 8 toolchain so the API class compiles to bytecode runnable on every supported MC server. Root project keeps default toolchain to coexist with the neoforge-1.21 subproject's Java 21 requirement.
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:bTTf2DEw:Loz1TUpf"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:bTTf2DEw:Loz1TUpf"
}

