From e454fef40e1e1e7a889327d3371fc7b5ff2b68df Mon Sep 17 00:00:00 2001 From: wiicart Date: Mon, 23 Jun 2025 22:50:59 -0400 Subject: [PATCH] Add support for private constructors in plugin main classes (#12652) --- .../paper/plugin/provider/util/ProviderUtil.java | 11 ++++++++++- .../org/bukkit/plugin/java/PluginClassLoader.java | 12 ++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java b/paper-api/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java index 48a67c1b60..5a1f30f9b5 100644 --- a/paper-api/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java +++ b/paper-api/src/main/java/io/papermc/paper/plugin/provider/util/ProviderUtil.java @@ -4,6 +4,8 @@ import com.destroystokyo.paper.util.SneakyThrow; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +import java.lang.reflect.Constructor; +import java.lang.reflect.InaccessibleObjectException; /** * An internal utility type that holds logic for loading a provider-like type from a classloaders. @@ -56,7 +58,14 @@ public final class ProviderUtil { throw new ClassCastException("class '%s' does not extend '%s'".formatted(clazz, classType)); } - clazzInstance = pluginClass.getDeclaredConstructor().newInstance(); + final Constructor constructor = pluginClass.getDeclaredConstructor(); + try { + constructor.setAccessible(true); // Allow non-public constructors + } catch (final InaccessibleObjectException | SecurityException ex) { + throw new RuntimeException("Inaccessible constructor"); + } + + clazzInstance = constructor.newInstance(); } catch (final IllegalAccessException exception) { throw new RuntimeException("No public constructor"); } catch (final InstantiationException exception) { diff --git a/paper-api/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/paper-api/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java index 37827b19e6..8c5a5043ad 100644 --- a/paper-api/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java +++ b/paper-api/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; +import java.lang.reflect.InaccessibleObjectException; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; @@ -91,13 +92,20 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm try { pluginConstructor = pluginClass.getDeclaredConstructor(); } catch (NoSuchMethodException ex) { - throw new InvalidPluginException("main class `" + description.getMain() + "' must have a public no-args constructor", ex); + throw new InvalidPluginException("main class `" + description.getMain() + "' must have a no-args constructor", ex); + } + + try { + // Support non-public constructors + pluginConstructor.setAccessible(true); + } catch (InaccessibleObjectException | SecurityException ex) { + throw new InvalidPluginException("main class `" + description.getMain() + "' constructor inaccessible", ex); } try { plugin = pluginConstructor.newInstance(); } catch (IllegalAccessException ex) { - throw new InvalidPluginException("main class `" + description.getMain() + "' constructor must be public", ex); + throw new InvalidPluginException("main class `" + description.getMain() + "' constructor inaccessible", ex); } catch (InstantiationException ex) { throw new InvalidPluginException("main class `" + description.getMain() + "' must not be abstract", ex); } catch (IllegalArgumentException ex) {