[SPIGOT-3723] Adding additional source URLs to the plugin classloader doesn't work Created: 29/Dec/17  Updated: 29/Dec/17  Resolved: 29/Dec/17

Status: Resolved
Project: Spigot
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: Luck Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: None
Environment:

Windows. Latest Spigot.

>version

[10:39:43 INFO]: This server is running CraftBukkit version git-Spigot-b66ad9e-b5a10a9 (MC: 1.12.2) (Implementing API version 1.12.2-R0.1-SNAPSHOT)

[10:39:43 INFO]: You are running the latest version

 



 Description   

Hi.

 

I use the following code in my plugin to inject additional dependency jars at runtime.

https://github.com/lucko/LuckPerms/blob/master/common/src/main/java/me/lucko/luckperms/common/dependencies/DependencyManager.java#L189-L202

 

This has worked fine in all Spigot/CraftBukkit builds until the recently.

Now, when an injected class is referenced and loaded, a ClassNotFoundException is thrown.

 

https://hastebin.com/afiseluniw.sql

 



 Comments   
Comment by Luck [ 29/Dec/17 ]

I'd support any kind of API addition which allowed for the injection of extra sources at runtime. Admittedly, it's fairly uncommon for plugins to use this approach to dependencies - the vast majority using shading. However, in my case, doing things this way is the difference between distributing a 1mb jar and distributing a 10mb jar (with that size likely to grow in the future as more storage strategies are added)

 

> a gentle attempt at breaking the incorrect assumption that the PluginClassLoader is a URLClassLoader (for various reasons, it should no longer be, but that would probably break more plugins).

 

Interestingly, a similar thing has occurred following the release of Java 9. On prior versions, ClassLoader#getSystemClassLoader returned a subclass of URLClassLoader, but no longer does in J9 - and yeah, same outcome, stuff breaks.

 

https://blog.codefx.org/java/java-9-migration-guide/#Casting-To-URL-Class-Loader

 

Thanks for resolving the issue. 

Comment by md_5 [ 29/Dec/17 ]

Efficiency issues (second dive into the jar), and a gentle attempt at breaking the incorrect assumption that the PluginClassLoader is a URLClassLoader (for various reasons, it should no longer be, but that would probably break more plugins).
I've reverted the change for the time being, but I think the only proper fix for this is to then add a library API for Bukkit

Comment by Luck [ 29/Dec/17 ]

Yep, I understand - however, as you point out, there's no defined way to load additional dependencies. I have to resort to relying on reflection.

 

I've tried to do as you suggest by:

  1. Creating a new URLClassLoader, and adding additional dependencies to that
  2. At the start of onEnable, setting the current threads context classloader to my own classloader

https://hastebin.com/lewaxumaze.scala

However, this still results in the same error - as it seems the classloader of the calling class is still used instead.

 

It's not really viable to use reflection to interact with all dependencies.

Instead of throwing an exception on PluginClassLoader line 122, could it not just delegate to super as it did previously?

https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/browse/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java#122

 

In other words, what does this commit address?

https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/commits/6d6f0c7fda94ee33f200e7d5eddc64240e7816d4

 

I appreciate you can't support plugins which rely on implementation details, but I don't see why the change was necessary.

 

Thanks for your quick reply.

Comment by md_5 [ 29/Dec/17 ]

I don’t think this is a bug.

1) You’re using reflection to access methods that you shouldn’t be.

2) Bukkit makes no guarantees that the classloader used to load your plugin is even a URLClassloader.

if you need to load libraries from external jars, you should be doing this by creating your own URLClassloader with your plugin classloader as the parent.

I understand that this may be viewed as a breaking change to Bukkit, but we cannot support random usage of reflection or assumptions that aren’t codified in the API.

Generated at Sun Mar 30 17:54:39 UTC 2025 using Jira 10.3.3#10030003-sha1:d220e3fefc8dfc6d47f522d3b9a20c1455e12b7b.