Skip to content

fix(minestom): configure shadowJar so the loader gets a real JarInJar#3

Open
TheMeinerLP wants to merge 1 commit into
masterfrom
claude/titan-minestom-deployment-XhoNO
Open

fix(minestom): configure shadowJar so the loader gets a real JarInJar#3
TheMeinerLP wants to merge 1 commit into
masterfrom
claude/titan-minestom-deployment-XhoNO

Conversation

@TheMeinerLP
Copy link
Copy Markdown

Problem

The published net.luckperms:minestom-loader:5.6-SNAPSHOT jar carries un-relocated net/kyori/adventure/** and net/bytebuddy/** at the top level. That defeats the JarInJar isolation and pins every consumer (Titan, etc.) to LuckPerms' bundled (older) Adventure version, causing runtime failures like:

ServiceConfigurationError: net.kyori.adventure.text.logger.slf4j.ComponentLoggerProvider:
Provider net.minestom.server.adventure.provider.MinestomComponentLoggerProvider could not be instantiated
Caused by: java.lang.NoSuchMethodError:
'net.kyori.adventure.util.Buildable$Builder net.kyori.adventure.text.flattener.ComponentFlattener.toBuilder()'
  at net.minestom.server.adventure.provider.MinestomFlattenerProvider.<clinit>(MinestomFlattenerProvider.java:14)
  at net.minestom.server.adventure.provider.MinestomComponentLoggerProvider.<clinit>(...)

…on modern Minestom (2026.05.17-1.21.11).

Root cause

:minestom/build.gradle declares the shadow plugin but has no shadowJar configuration:

  • the output is <name>-all.jar (plain .jar extension), and
  • it performs no relocations.

:minestom/loader/build.gradle then embeds the file via

shadowJar {
    from { project(':minestom').tasks.shadowJar.archiveFile }
}

Because the input is a .jar, the Shadow plugin unzips it into the outer loader jar. Combined with the missing relocations, the loader jar ends up with net/kyori/adventure/** and net/bytebuddy/** at top level instead of carrying the inner shadow jar as a single resource.

Fix

Mirror the :velocity shadowJar configuration (the closest analogue, since Velocity is also an Adventure-native platform):

  • archiveFileName = 'luckperms-minestom.jarinjar' — Shadow does not unzip non-.jar inputs, so the loader's from copies the file verbatim; the name also matches the JAR_NAME constant in MinestomLoader.java that the JarInJarClassLoader looks up at runtime.
  • The exact same relocate set as :velocity (adventure, event, caffeine, okio, okhttp3, bytebuddy, commodore, mariadb, mysql, postgresql, hikari, mongodb, bson, jedis, nats, rabbitmq, commons-pool2, configurate, snakeyaml).
  • artifacts { archives shadowJar } so the loader picks up the configured archive.

Effect

After this change, minestom-loader-5.6-SNAPSHOT.jar contains luckperms-minestom.jarinjar as a single resource (no top-level net/kyori/adventure/**) and the embedded LuckPerms platform runs inside its JarInJar-isolated classloader as designed — restoring the same isolation guarantees the Bukkit/Velocity loaders already provide.

Test plan

  • CI builds :minestom:shadowJar and :minestom:loader:shadowJar successfully.
  • Inspect minestom-loader-<ver>.jar: top-level entries are me/lucko/..., META-INF/, luckperms-minestom.jarinjar — and no net/kyori/adventure/** or net/bytebuddy/** at the top level.
  • 5.6-SNAPSHOT deploys to the OLF snapshots repo.
  • Downstream Titan smoke test: server boots, LuckPermsProvider.get() works, no Adventure NoSuchMethodError on Minestom 2026.05.17-1.21.11.

Generated by Claude Code

The :minestom module declared the shadow plugin but had no shadowJar
configuration, so its output was a plain <name>-all.jar with no
relocations. :minestom/loader/build.gradle then embeds that file via
`from { project(':minestom').tasks.shadowJar.archiveFile }`, which the
Shadow plugin unzips because the file has a .jar extension. Result: the
published net.luckperms:minestom-loader jar carries un-relocated
net/kyori/adventure/** and net/bytebuddy/** at the top level, defeating
the JarInJar isolation and pinning every consumer (Titan, etc.) to
LuckPerms' bundled Adventure version. Visible in the published artifact.

Mirror the :velocity shadowJar config (closest adventure-native analogue):
- archiveFileName = 'luckperms-minestom.jarinjar' so the loader's `from`
  copies it verbatim (Shadow does not unzip non-.jar inputs) and so the
  JarInJarClassLoader resource lookup matches MinestomLoader's JAR_NAME
- the same relocate set as :velocity (adventure, event, caffeine, okio,
  okhttp3, bytebuddy, commodore, mariadb, mysql, postgresql, hikari,
  mongodb, bson, jedis, nats, rabbitmq, commonspool2, configurate, yaml)
- artifacts { archives shadowJar } so the loader picks up the new file

After this, minestom-loader-5.6-SNAPSHOT.jar contains
luckperms-minestom.jarinjar as a single resource (no top-level
net/kyori/adventure/**) and the embedded LuckPerms platform runs in its
JarInJar-isolated classloader as designed.

https://claude.ai/code/session_01S76fk9ma5Szkf9r1W44RVP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants