Finish converting most of the undeprecated api to jspecify

This commit is contained in:
Jake Potrebic 2024-09-30 11:44:36 -07:00
parent ba3c29b92e
commit e7e1ab56ca
No known key found for this signature in database
GPG key ID: ECE0B3C133C016C5
45 changed files with 1046 additions and 982 deletions

View file

@ -27,26 +27,26 @@ index 1f627e81622e77b81b1228a467fbb9e6fd979e7a..3c50362de25617d878ef58f14f67c240
diff --git a/src/main/java/io/papermc/paper/plugin/PermissionManager.java b/src/main/java/io/papermc/paper/plugin/PermissionManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c27846933
index 0000000000000000000000000000000000000000..c78ada48e27c5552529fe8d5bc23db1dac94e481
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/PermissionManager.java
@@ -0,0 +1,171 @@
@@ -0,0 +1,166 @@
+package io.papermc.paper.plugin;
+
+import org.bukkit.permissions.Permissible;
+import org.bukkit.permissions.Permission;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Set;
+import org.bukkit.permissions.Permissible;
+import org.bukkit.permissions.Permission;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * A permission manager implementation to keep backwards compatibility partially alive with existing plugins that used
+ * the bukkit one before.
+ */
+@ApiStatus.Experimental
+@NullMarked
+public interface PermissionManager {
+
+ /**
@ -55,8 +55,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param name Name of the permission
+ * @return Permission, or null if none
+ */
+ @Nullable
+ Permission getPermission(@NotNull String name);
+ @Nullable Permission getPermission(String name);
+
+ /**
+ * Adds a {@link Permission} to this plugin manager.
@ -68,7 +67,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @throws IllegalArgumentException Thrown when a permission with the same
+ * name already exists
+ */
+ void addPermission(@NotNull Permission perm);
+ void addPermission(Permission perm);
+
+ /**
+ * Removes a {@link Permission} registration from this plugin manager.
@ -81,7 +80,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @param perm Permission to remove
+ */
+ void removePermission(@NotNull Permission perm);
+ void removePermission(Permission perm);
+
+ /**
+ * Removes a {@link Permission} registration from this plugin manager.
@ -94,7 +93,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @param name Permission to remove
+ */
+ void removePermission(@NotNull String name);
+ void removePermission(String name);
+
+ /**
+ * Gets the default permissions for the given op status
@ -102,7 +101,6 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param op Which set of default permissions to get
+ * @return The default permissions
+ */
+ @NotNull
+ Set<Permission> getDefaultPermissions(boolean op);
+
+ /**
@ -113,7 +111,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @param perm Permission to recalculate
+ */
+ void recalculatePermissionDefaults(@NotNull Permission perm);
+ void recalculatePermissionDefaults(Permission perm);
+
+ /**
+ * Subscribes the given Permissible for information about the requested
@ -125,7 +123,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param permission Permission to subscribe to
+ * @param permissible Permissible subscribing
+ */
+ void subscribeToPermission(@NotNull String permission, @NotNull Permissible permissible);
+ void subscribeToPermission(String permission, Permissible permissible);
+
+ /**
+ * Unsubscribes the given Permissible for information about the requested
@ -134,7 +132,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param permission Permission to unsubscribe from
+ * @param permissible Permissible subscribing
+ */
+ void unsubscribeFromPermission(@NotNull String permission, @NotNull Permissible permissible);
+ void unsubscribeFromPermission(String permission, Permissible permissible);
+
+ /**
+ * Gets a set containing all subscribed {@link Permissible}s to the given
@ -143,8 +141,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param permission Permission to query for
+ * @return Set containing all subscribed permissions
+ */
+ @NotNull
+ Set<Permissible> getPermissionSubscriptions(@NotNull String permission);
+ Set<Permissible> getPermissionSubscriptions(String permission);
+
+ /**
+ * Subscribes to the given Default permissions by operator status
@ -155,7 +152,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param op Default list to subscribe to
+ * @param permissible Permissible subscribing
+ */
+ void subscribeToDefaultPerms(boolean op, @NotNull Permissible permissible);
+ void subscribeToDefaultPerms(boolean op, Permissible permissible);
+
+ /**
+ * Unsubscribes from the given Default permissions by operator status
@ -163,7 +160,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param op Default list to unsubscribe from
+ * @param permissible Permissible subscribing
+ */
+ void unsubscribeFromDefaultPerms(boolean op, @NotNull Permissible permissible);
+ void unsubscribeFromDefaultPerms(boolean op, Permissible permissible);
+
+ /**
+ * Gets a set containing all subscribed {@link Permissible}s to the given
@ -172,7 +169,6 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ * @param op Default list to query for
+ * @return Set containing all subscribed permissions
+ */
+ @NotNull
+ Set<Permissible> getDefaultPermSubscriptions(boolean op);
+
+ /**
@ -182,7 +178,6 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @return Set containing all current registered permissions
+ */
+ @NotNull
+ Set<Permission> getPermissions();
+
+ /**
@ -192,7 +187,7 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+ *
+ * @param perm permission
+ */
+ void addPermissions(@NotNull List<Permission> perm);
+ void addPermissions(List<Permission> perm);
+
+ /**
+ * Clears the current registered permissinos.
@ -204,13 +199,14 @@ index 0000000000000000000000000000000000000000..cdbc93b317b3bab47bf6552c29cfbb2c
+}
diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..70d5f9802f90605a5120ff2a000a2e9395f0aecc
index 0000000000000000000000000000000000000000..4c47414fc08e1183b1e59369bacc4d7f7042f262
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/BootstrapContext.java
@@ -0,0 +1,14 @@
@@ -0,0 +1,16 @@
+package io.papermc.paper.plugin.bootstrap;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents the context provided to a {@link PluginBootstrap} during both the bootstrapping and plugin
@ -219,12 +215,13 @@ index 0000000000000000000000000000000000000000..70d5f9802f90605a5120ff2a000a2e93
+ * like the plugin's configuration or logger during the plugins bootstrap.
+ */
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.NonExtendable
+public interface BootstrapContext extends PluginProviderContext {
+}
diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java
new file mode 100644
index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8d287a11f
index 0000000000000000000000000000000000000000..e6696dcd8049e869bd1733f7c67ff802c54d7c37
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginBootstrap.java
@@ -0,0 +1,41 @@
@ -233,7 +230,7 @@ index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8
+import io.papermc.paper.plugin.provider.util.ProviderUtil;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A plugin bootstrap is meant for loading certain parts of the plugin before the server is loaded.
@ -245,8 +242,9 @@ index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8
+ * <p>
+ * <b>All calls to Bukkit may throw a NullPointerExceptions or return null unexpectedly. You should only call api methods that are explicitly documented to work in the bootstrapper</b>
+ */
+@ApiStatus.OverrideOnly
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.OverrideOnly
+public interface PluginBootstrap {
+
+ /**
@ -254,7 +252,7 @@ index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8
+ *
+ * @param context the server provided context
+ */
+ void bootstrap(@NotNull BootstrapContext context);
+ void bootstrap(BootstrapContext context);
+
+ /**
+ * Called by the server to instantiate your main class.
@ -264,25 +262,23 @@ index 0000000000000000000000000000000000000000..81e09abd2128d8cc54d1fd6454aea7d8
+ * @param context the server created bootstrap object
+ * @return the server requested instance of the plugins main class.
+ */
+ @NotNull
+ default JavaPlugin createPlugin(@NotNull PluginProviderContext context) {
+ default JavaPlugin createPlugin(final PluginProviderContext context) {
+ return ProviderUtil.loadClass(context.getConfiguration().getMainClass(), JavaPlugin.class, this.getClass().getClassLoader());
+ }
+}
diff --git a/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba46282bea5d1a
index 0000000000000000000000000000000000000000..19bb302ab264b72306d9bd15e9c40ade6dde7ee7
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/bootstrap/PluginProviderContext.java
@@ -0,0 +1,52 @@
@@ -0,0 +1,48 @@
+package io.papermc.paper.plugin.bootstrap;
+
+import io.papermc.paper.plugin.configuration.PluginMeta;
+import java.nio.file.Path;
+import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.nio.file.Path;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents the context provided to a {@link PluginBootstrap} during both the bootstrapping and plugin
@ -290,8 +286,9 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ * A bootstrap context may be used to access data or logic usually provided to {@link org.bukkit.plugin.Plugin} instances
+ * like the plugin's configuration or logger during the plugins bootstrap.
+ */
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.NonExtendable
+public interface PluginProviderContext {
+
+ /**
@ -299,7 +296,6 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ *
+ * @return the plugin's configuration
+ */
+ @NotNull
+ PluginMeta getConfiguration();
+
+ /**
@ -307,7 +303,6 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ *
+ * @return the previously described path
+ */
+ @NotNull
+ Path getDataDirectory();
+
+ /**
@ -315,7 +310,6 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ *
+ * @return the logger instance
+ */
+ @NotNull
+ ComponentLogger getLogger();
+
+ /**
@ -323,33 +317,32 @@ index 0000000000000000000000000000000000000000..c1ce2a8bdf2e3bd9ad2fc7f32fba4628
+ *
+ * @return the previously described path
+ */
+ @NotNull
+ Path getPluginSource();
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java b/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java
new file mode 100644
index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9ada2e585f
index 0000000000000000000000000000000000000000..3c768d5ccf490e962d9638e92d4ea7c85670bad8
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/configuration/PluginMeta.java
@@ -0,0 +1,203 @@
@@ -0,0 +1,186 @@
+package io.papermc.paper.plugin.configuration;
+
+import java.util.List;
+import org.bukkit.permissions.Permission;
+import org.bukkit.permissions.PermissionDefault;
+import org.bukkit.plugin.PluginLoadOrder;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * This class acts as an abstraction for a plugin configuration.
+ */
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental // Subject to change!
+@NullMarked
+@ApiStatus.NonExtendable
+public interface PluginMeta {
+
+ /**
@ -369,7 +362,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return the name of the plugin
+ */
+ @NotNull
+ String getName();
+
+ /**
@ -377,7 +369,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return a descriptive name of the plugin and respective version
+ */
+ @NotNull
+ default String getDisplayName() {
+ return this.getName() + " v" + this.getVersion();
+ }
@ -388,7 +379,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return the fully qualified class name of the plugin's main class.
+ */
+ @NotNull
+ String getMainClass();
+
+ /**
@ -397,7 +387,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @return the plugin load order
+ * @see PluginLoadOrder for further details regards the available load orders.
+ */
+ @NotNull
+ PluginLoadOrder getLoadOrder();
+
+ /**
@ -407,7 +396,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return the string representation of the plugin's version
+ */
+ @NotNull
+ String getVersion();
+
+ /**
@ -418,8 +406,7 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @return the specific overwrite of the logger prefix as defined by the plugin. If the plugin did not define a
+ * custom logger prefix, this method will return null
+ */
+ @Nullable
+ String getLoggerPrefix();
+ @Nullable String getLoggerPrefix();
+
+ /**
+ * Provides a list of dependencies that are required for this plugin to load.
@ -430,7 +417,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return an immutable list of required dependency names
+ */
+ @NotNull
+ List<String> getPluginDependencies();
+
+ /**
@ -443,7 +429,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return immutable list of soft dependencies
+ */
+ @NotNull
+ List<String> getPluginSoftDependencies();
+
+ /**
@ -456,7 +441,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return immutable list of plugins to load before this plugin
+ */
+ @NotNull
+ List<String> getLoadBeforePlugins();
+
+ /**
@ -466,7 +450,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return immutable list of provided plugins/dependencies
+ */
+ @NotNull
+ List<String> getProvidedPlugins();
+
+ /**
@ -475,7 +458,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return an immutable list of the plugin's authors
+ */
+ @NotNull
+ List<String> getAuthors();
+
+ /**
@ -484,7 +466,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return an immutable list of the plugin's contributors
+ */
+ @NotNull
+ List<String> getContributors();
+
+ /**
@ -493,8 +474,7 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return description or null if the plugin did not define a human readable description.
+ */
+ @Nullable
+ String getDescription();
+ @Nullable String getDescription();
+
+ /**
+ * Provides the website for the plugin or the plugin's author.
@ -502,8 +482,7 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ *
+ * @return a string representation of the website that serves as the main hub for this plugin/its author.
+ */
+ @Nullable
+ String getWebsite();
+ @Nullable String getWebsite();
+
+ /**
+ * Provides the list of permissions that are defined via the plugin meta instance.
@ -511,7 +490,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @return an immutable list of permissions
+ */
+ // TODO: Do we even want this? Why not just use the bootstrapper
+ @NotNull
+ List<Permission> getPermissions();
+
+ /**
@ -521,7 +499,6 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @see #getPermissions()
+ */
+ // TODO: Do we even want this? Why not just use the bootstrapper
+ @NotNull
+ PermissionDefault getPermissionDefault();
+
+ /**
@ -532,8 +509,7 @@ index 0000000000000000000000000000000000000000..bcf91d048d84144f6acf9bfd2095df9a
+ * @return the version string made up of the major and minor version (e.g. 1.18 or 1.19). Minor versions like 1.18.2
+ * are unified to their major release version (in this example 1.18)
+ */
+ @Nullable
+ String getAPIVersion();
+ @Nullable String getAPIVersion();
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/configuration/package-info.java b/src/main/java/io/papermc/paper/plugin/configuration/package-info.java
@ -552,10 +528,10 @@ index 0000000000000000000000000000000000000000..ddb3076124365d0d1a5caa32d4dcb1f4
+package io.papermc.paper.plugin.configuration;
diff --git a/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java b/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..28cbc09b7c1ded1f4515969cef4a669adac85703
index 0000000000000000000000000000000000000000..ddb768057cdfd9202e4386494fd5f643692c73a1
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/PluginClasspathBuilder.java
@@ -0,0 +1,38 @@
@@ -0,0 +1,37 @@
+package io.papermc.paper.plugin.loader;
+
+import io.papermc.paper.plugin.bootstrap.PluginProviderContext;
@ -563,14 +539,15 @@ index 0000000000000000000000000000000000000000..28cbc09b7c1ded1f4515969cef4a669a
+import io.papermc.paper.plugin.loader.library.LibraryStore;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A mutable builder that may be used to collect and register all {@link ClassPathLibrary} instances a
+ * {@link PluginLoader} aims to provide to its plugin at runtime.
+ */
+@ApiStatus.NonExtendable
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.NonExtendable
+public interface PluginClasspathBuilder {
+
+ /**
@ -587,23 +564,21 @@ index 0000000000000000000000000000000000000000..28cbc09b7c1ded1f4515969cef4a669a
+ * @see io.papermc.paper.plugin.loader.library.impl.JarLibrary
+ * @see io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver
+ */
+ @NotNull
+ @Contract("_ -> this")
+ PluginClasspathBuilder addLibrary(@NotNull ClassPathLibrary classPathLibrary);
+ PluginClasspathBuilder addLibrary(ClassPathLibrary classPathLibrary);
+
+ @NotNull
+ PluginProviderContext getContext();
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java b/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..c9e31f78ff6ff969436c6d99755845786c4d383f
index 0000000000000000000000000000000000000000..c2d029e4474cc00c84e5b3f7fceec4c3f30b486b
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/PluginLoader.java
@@ -0,0 +1,30 @@
@@ -0,0 +1,31 @@
+package io.papermc.paper.plugin.loader;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A plugin loader is responsible for creating certain aspects of a plugin before it is created.
@ -615,8 +590,9 @@ index 0000000000000000000000000000000000000000..c9e31f78ff6ff969436c6d9975584578
+ * It should be noted that this class will be called from a different classloader, this will cause any static values
+ * set in this class/any other classes loaded not to persist when the plugin loads.
+ */
+@ApiStatus.OverrideOnly
+@ApiStatus.Experimental
+@NullMarked
+@ApiStatus.OverrideOnly
+public interface PluginLoader {
+
+ /**
@ -627,23 +603,24 @@ index 0000000000000000000000000000000000000000..c9e31f78ff6ff969436c6d9975584578
+ * @param classpathBuilder a mutable classpath builder that may be used to register custom runtime dependencies
+ * for the plugin the loader was registered for.
+ */
+ void classloader(@NotNull PluginClasspathBuilder classpathBuilder);
+ void classloader(PluginClasspathBuilder classpathBuilder);
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java b/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java
new file mode 100644
index 0000000000000000000000000000000000000000..1347b535d90c2c281c184d0459e7ac59c0350c9f
index 0000000000000000000000000000000000000000..8a07333a592056bab1d26d811316bb5ea5f30e18
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/ClassPathLibrary.java
@@ -0,0 +1,20 @@
@@ -0,0 +1,21 @@
+package io.papermc.paper.plugin.loader.library;
+
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * The classpath library interface represents libraries that are capable of registering themselves via
+ * {@link #register(LibraryStore)} on any given {@link LibraryStore}.
+ */
+@NullMarked
+public interface ClassPathLibrary {
+
+ /**
@ -654,7 +631,7 @@ index 0000000000000000000000000000000000000000..1347b535d90c2c281c184d0459e7ac59
+ * @param store the library store instance to register this library into
+ * @throws LibraryLoadingException if library loading failed for this classpath library
+ */
+ void register(@NotNull LibraryStore store) throws LibraryLoadingException;
+ void register(LibraryStore store) throws LibraryLoadingException;
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/LibraryLoadingException.java b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryLoadingException.java
new file mode 100644
@ -679,16 +656,15 @@ index 0000000000000000000000000000000000000000..79ba423a364b50588f3ee87fdc69155c
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/LibraryStore.java b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryStore.java
new file mode 100644
index 0000000000000000000000000000000000000000..0546fa1e9dcd7155086a8650806a8c086b6fc458
index 0000000000000000000000000000000000000000..93ef8e369a158c25bc4fdd553faf13c1826ad872
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/LibraryStore.java
@@ -0,0 +1,26 @@
+package io.papermc.paper.plugin.loader.library;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.nio.file.Path;
+import org.jetbrains.annotations.ApiStatus;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Represents a storage that stores library jars.
@ -699,6 +675,7 @@ index 0000000000000000000000000000000000000000..0546fa1e9dcd7155086a8650806a8c08
+ * @see io.papermc.paper.plugin.loader.PluginLoader
+ */
+@ApiStatus.Internal
+@NullMarked
+public interface LibraryStore {
+
+ /**
@ -706,12 +683,12 @@ index 0000000000000000000000000000000000000000..0546fa1e9dcd7155086a8650806a8c08
+ *
+ * @param library path to the libraries jar file on the disk
+ */
+ void addLibrary(@NotNull Path library);
+ void addLibrary(Path library);
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java b/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff25961ee79fb
index 0000000000000000000000000000000000000000..9efcd9a62d6439eb27fc4e08498b4b7fbbdecb3c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/JarLibrary.java
@@ -0,0 +1,45 @@
@ -720,10 +697,9 @@ index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff259
+import io.papermc.paper.plugin.loader.library.ClassPathLibrary;
+import io.papermc.paper.plugin.loader.library.LibraryLoadingException;
+import io.papermc.paper.plugin.loader.library.LibraryStore;
+import org.jetbrains.annotations.NotNull;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A simple jar library implementation of the {@link ClassPathLibrary} that allows {@link io.papermc.paper.plugin.loader.PluginLoader}s to
@ -738,6 +714,7 @@ index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff259
+ * <p>
+ * The jar library implementation will error if the file does not exist at the specified path.
+ */
+@NullMarked
+public class JarLibrary implements ClassPathLibrary {
+
+ private final Path path;
@ -747,12 +724,12 @@ index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff259
+ *
+ * @param path the path, relative to the JVMs start directory.
+ */
+ public JarLibrary(@NotNull Path path) {
+ public JarLibrary(final Path path) {
+ this.path = path;
+ }
+
+ @Override
+ public void register(@NotNull LibraryStore store) throws LibraryLoadingException {
+ public void register(final LibraryStore store) throws LibraryLoadingException {
+ if (Files.notExists(this.path)) {
+ throw new LibraryLoadingException("Could not find library at " + this.path);
+ }
@ -762,7 +739,7 @@ index 0000000000000000000000000000000000000000..e3da0d67cab01e1233dccde1a12ff259
+}
diff --git a/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19a94791ab
index 0000000000000000000000000000000000000000..107705db2d82b7c191e5e625ec888e0bc3b03831
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/loader/library/impl/MavenLibraryResolver.java
@@ -0,0 +1,133 @@
@ -771,6 +748,9 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+import io.papermc.paper.plugin.loader.library.ClassPathLibrary;
+import io.papermc.paper.plugin.loader.library.LibraryLoadingException;
+import io.papermc.paper.plugin.loader.library.LibraryStore;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
@ -791,14 +771,10 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+import org.eclipse.aether.transfer.TransferCancelledException;
+import org.eclipse.aether.transfer.TransferEvent;
+import org.eclipse.aether.transport.http.HttpTransporterFactory;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The maven library resolver acts as a resolver for yet to be resolved jar libraries that may be pulled from a
+ * remote maven repository.
@ -813,12 +789,13 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * "central", "default", "https://repo1.maven.org/maven2/"
+ * ).build());
+ * }</pre>
+ *
+ * <p>
+ * Plugins may create and register a {@link MavenLibraryResolver} after configuring it.
+ */
+@NullMarked
+public class MavenLibraryResolver implements ClassPathLibrary {
+
+ private static final Logger logger = LoggerFactory.getLogger("MavenLibraryResolver");
+ private static final Logger LOGGER = LoggerFactory.getLogger("MavenLibraryResolver");
+
+ private final RepositorySystem repository;
+ private final DefaultRepositorySystemSession session;
@ -834,7 +811,7 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * submitting the {@link MavenLibraryResolver} to the {@link io.papermc.paper.plugin.loader.PluginClasspathBuilder}.
+ */
+ public MavenLibraryResolver() {
+ DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
+ final DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
+ locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
+ locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
+
@ -846,8 +823,8 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ this.session.setLocalRepositoryManager(this.repository.newLocalRepositoryManager(this.session, new LocalRepository("libraries")));
+ this.session.setTransferListener(new AbstractTransferListener() {
+ @Override
+ public void transferInitiated(@NotNull TransferEvent event) throws TransferCancelledException {
+ logger.info("Downloading {}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ public void transferInitiated(final TransferEvent event) throws TransferCancelledException {
+ LOGGER.info("Downloading {}", event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
+ }
+ });
+ this.session.setReadOnly();
@ -860,7 +837,7 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * @param dependency the definition of the dependency the maven library resolver should resolve when running
+ * @see MavenLibraryResolver#addRepository(RemoteRepository)
+ */
+ public void addDependency(@NotNull Dependency dependency) {
+ public void addDependency(final Dependency dependency) {
+ this.dependencies.add(dependency);
+ }
+
@ -870,9 +847,9 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * repository.
+ *
+ * @param remoteRepository the configuration that defines the maven repository this library resolver should fetch
+ * dependencies from
+ * dependencies from
+ */
+ public void addRepository(@NotNull RemoteRepository remoteRepository) {
+ public void addRepository(final RemoteRepository remoteRepository) {
+ this.repositories.add(remoteRepository);
+ }
+
@ -883,32 +860,32 @@ index 0000000000000000000000000000000000000000..70f352630de71f575d1aea5a3126da19
+ * @throws LibraryLoadingException if resolving a dependency failed
+ */
+ @Override
+ public void register(@NotNull LibraryStore store) throws LibraryLoadingException {
+ List<RemoteRepository> repos = this.repository.newResolutionRepositories(this.session, this.repositories);
+ public void register(final LibraryStore store) throws LibraryLoadingException {
+ final List<RemoteRepository> repos = this.repository.newResolutionRepositories(this.session, this.repositories);
+
+ DependencyResult result;
+ final DependencyResult result;
+ try {
+ result = this.repository.resolveDependencies(this.session, new DependencyRequest(new CollectRequest((Dependency) null, this.dependencies, repos), null));
+ } catch (DependencyResolutionException ex) {
+ } catch (final DependencyResolutionException ex) {
+ throw new LibraryLoadingException("Error resolving libraries", ex);
+ }
+
+ for (ArtifactResult artifact : result.getArtifactResults()) {
+ File file = artifact.getArtifact().getFile();
+ for (final ArtifactResult artifact : result.getArtifactResults()) {
+ final File file = artifact.getArtifact().getFile();
+ store.addLibrary(file.toPath());
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..64e46fdfa4d404cb08c67a456e5990b729296b98
index 0000000000000000000000000000000000000000..75fe408ec742319c3cba2461b33b2a6e8b22d231
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/ClassLoaderAccess.java
@@ -0,0 +1,34 @@
@@ -0,0 +1,35 @@
+package io.papermc.paper.plugin.provider.classloader;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * The class loader access interface is an <b>internal</b> representation of a class accesses' ability to see types
@ -919,6 +896,7 @@ index 0000000000000000000000000000000000000000..64e46fdfa4d404cb08c67a456e5990b7
+ * is owned by a direct or transitive dependency of the plugin, preventing the plugin for accidentally discovering and
+ * using class types that are supplied by plugins/libraries the plugin did not actively define as a dependency.
+ */
+@NullMarked
+@ApiStatus.Internal
+public interface ClassLoaderAccess {
+
@ -941,19 +919,18 @@ index 0000000000000000000000000000000000000000..64e46fdfa4d404cb08c67a456e5990b7
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java
new file mode 100644
index 0000000000000000000000000000000000000000..a21bdc57564aef7caf43dde3b2bcb2fc7f30461c
index 0000000000000000000000000000000000000000..7c23e0a1a38f8b89484aee160647f751088903cd
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/ConfiguredPluginClassLoader.java
@@ -0,0 +1,71 @@
@@ -0,0 +1,70 @@
+package io.papermc.paper.plugin.provider.classloader;
+
+import io.papermc.paper.plugin.configuration.PluginMeta;
+import java.io.Closeable;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.Closeable;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * The configured plugin class loader represents an <b>internal</b> abstraction over the classloaders used by the server
@ -962,6 +939,7 @@ index 0000000000000000000000000000000000000000..a21bdc57564aef7caf43dde3b2bcb2fc
+ * It implements {@link Closeable} to define the ability to shutdown and close the classloader that implements this
+ * interface.
+ */
+@NullMarked
+@ApiStatus.Internal
+public interface ConfiguredPluginClassLoader extends Closeable {
+
@ -987,7 +965,7 @@ index 0000000000000000000000000000000000000000..a21bdc57564aef7caf43dde3b2bcb2fc
+ * @see ClassLoader#loadClass(String)
+ * @see Class#forName(String, boolean, ClassLoader)
+ */
+ Class<?> loadClass(@NotNull String name,
+ Class<?> loadClass(String name,
+ boolean resolve,
+ boolean checkGlobal,
+ boolean checkLibraries) throws ClassNotFoundException;
@ -1013,8 +991,7 @@ index 0000000000000000000000000000000000000000..a21bdc57564aef7caf43dde3b2bcb2fc
+ * that is used by the underlying classloader
+ * @return classloader
+ */
+ @Nullable
+ PluginClassLoaderGroup getGroup();
+ @Nullable PluginClassLoaderGroup getGroup();
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorage.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/PaperClassLoaderStorage.java
new file mode 100644
@ -1139,15 +1116,16 @@ index 0000000000000000000000000000000000000000..2c0e5ba6f8eba7a632180491843071b8
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java b/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java
new file mode 100644
index 0000000000000000000000000000000000000000..885151cb932d9b8c09a7887edc879e154225f416
index 0000000000000000000000000000000000000000..dd3bfbf8a30c9ac6a82dcbdf879bbf120d920e20
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/classloader/PluginClassLoaderGroup.java
@@ -0,0 +1,65 @@
@@ -0,0 +1,66 @@
+package io.papermc.paper.plugin.provider.classloader;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * A plugin classloader group represents a group of classloaders that a plugins classloader may access.
@ -1155,6 +1133,7 @@ index 0000000000000000000000000000000000000000..885151cb932d9b8c09a7887edc879e15
+ * An example of this would be a classloader group that holds all direct and transitive dependencies a plugin declared,
+ * allowing a plugins classloader to access classes included in these dependencies via this group.
+ */
+@NullMarked
+@ApiStatus.Internal
+public interface PluginClassLoaderGroup {
+
@ -1172,8 +1151,7 @@ index 0000000000000000000000000000000000000000..885151cb932d9b8c09a7887edc879e15
+ * will be returned.
+ * @see ConfiguredPluginClassLoader#loadClass(String, boolean, boolean, boolean)
+ */
+ @Nullable
+ Class<?> getClassByName(String name, boolean resolve, ConfiguredPluginClassLoader requester);
+ @Nullable Class<?> getClassByName(String name, boolean resolve, ConfiguredPluginClassLoader requester);
+
+ /**
+ * Removes a configured plugin classloader from this class loader group.
@ -1210,15 +1188,15 @@ index 0000000000000000000000000000000000000000..885151cb932d9b8c09a7887edc879e15
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java b/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java
new file mode 100644
index 0000000000000000000000000000000000000000..44d630c3eb2670c36134b9907519dc986b3761b4
index 0000000000000000000000000000000000000000..338dc25d5161b7378dd17b17d6f603c92eb0a894
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/entrypoint/DependencyContext.java
@@ -0,0 +1,48 @@
@@ -0,0 +1,49 @@
+package io.papermc.paper.plugin.provider.entrypoint;
+
+import io.papermc.paper.plugin.configuration.PluginMeta;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * A dependency context is a read-only abstraction of a type/concept that can resolve dependencies between plugins.
@ -1226,6 +1204,7 @@ index 0000000000000000000000000000000000000000..44d630c3eb2670c36134b9907519dc98
+ * This may for example be the server wide plugin manager itself, capable of validating if a dependency exists between
+ * two {@link PluginMeta} instances, however the implementation is not limited to such a concrete use-case.
+ */
+@NullMarked
+@ApiStatus.Internal
+public interface DependencyContext {
+
@ -1245,7 +1224,7 @@ index 0000000000000000000000000000000000000000..44d630c3eb2670c36134b9907519dc98
+ * @param depend the potential transitive dependency of the {@code plugin} parameter.
+ * @return a simple boolean flag indicating if {@code plugin} considers {@code depend} as a transitive dependency.
+ */
+ boolean isTransitiveDependency(@NotNull PluginMeta plugin, @NotNull PluginMeta depend);
+ boolean isTransitiveDependency(PluginMeta plugin, PluginMeta depend);
+
+ /**
+ * Computes if this dependency context is aware of a dependency that provides/matches the passed identifier.
@ -1259,29 +1238,30 @@ index 0000000000000000000000000000000000000000..44d630c3eb2670c36134b9907519dc98
+ * @return a plain boolean flag indicating if this dependency context is aware of a potential dependency with the
+ * passed identifier.
+ */
+ boolean hasDependency(@NotNull String pluginIdentifier);
+ boolean hasDependency(String pluginIdentifier);
+
+}
diff --git a/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java b/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..6bf3d212a6156ad9ab0e82d1ca0a04f83f6e4b83
index 0000000000000000000000000000000000000000..48a67c1b6070292dbf4ea3081f89b530207f9f6d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java
@@ -0,0 +1,78 @@
@@ -0,0 +1,77 @@
+package io.papermc.paper.plugin.provider.util;
+
+import com.destroystokyo.paper.util.SneakyThrow;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jspecify.annotations.NullMarked;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * An <b>internal</b> utility type that holds logic for loading a provider-like type from a classloaders.
+ * Provides, at least in the context of this utility, define themselves as implementations of a specific parent
+ * interface/type, e.g. {@link org.bukkit.plugin.java.JavaPlugin} and implement a no-args constructor.
+ */
+@NullMarked
+@ApiStatus.Internal
+public class ProviderUtil {
+public final class ProviderUtil {
+
+ /**
+ * Loads the class found at the provided fully qualified class name from the passed classloader, creates a new
@ -1294,8 +1274,7 @@ index 0000000000000000000000000000000000000000..6bf3d212a6156ad9ab0e82d1ca0a04f8
+ * @param <T> the generic type of the parent class the created object will be cast to
+ * @return the object instantiated from the class found at the provided FQN, cast to the parent type
+ */
+ @NotNull
+ public static <T> T loadClass(@NotNull String clazz, @NotNull Class<T> classType, @NotNull ClassLoader loader) {
+ public static <T> T loadClass(final String clazz, final Class<T> classType, final ClassLoader loader) {
+ return loadClass(clazz, classType, loader, null);
+ }
+
@ -1312,30 +1291,29 @@ index 0000000000000000000000000000000000000000..6bf3d212a6156ad9ab0e82d1ca0a04f8
+ * @return the object instantiated from the class found at the provided fully qualified class name, cast to the
+ * parent type
+ */
+ @NotNull
+ public static <T> T loadClass(@NotNull String clazz, @NotNull Class<T> classType, @NotNull ClassLoader loader, @Nullable Runnable onError) {
+ public static <T> T loadClass(final String clazz, final Class<T> classType, final ClassLoader loader, final @Nullable Runnable onError) {
+ try {
+ T clazzInstance;
+ final T clazzInstance;
+
+ try {
+ Class<?> jarClass = Class.forName(clazz, true, loader);
+ final Class<?> jarClass = Class.forName(clazz, true, loader);
+
+ Class<? extends T> pluginClass;
+ final Class<? extends T> pluginClass;
+ try {
+ pluginClass = jarClass.asSubclass(classType);
+ } catch (ClassCastException ex) {
+ } catch (final ClassCastException ex) {
+ throw new ClassCastException("class '%s' does not extend '%s'".formatted(clazz, classType));
+ }
+
+ clazzInstance = pluginClass.getDeclaredConstructor().newInstance();
+ } catch (IllegalAccessException exception) {
+ } catch (final IllegalAccessException exception) {
+ throw new RuntimeException("No public constructor");
+ } catch (InstantiationException exception) {
+ } catch (final InstantiationException exception) {
+ throw new RuntimeException("Abnormal class instantiation", exception);
+ }
+
+ return clazzInstance;
+ } catch (Throwable e) {
+ } catch (final Throwable e) {
+ if (onError != null) {
+ onError.run();
+ }