Allow extensions to opt to be added to the parent classloader instead

This commit is contained in:
Luck 2021-02-19 16:25:11 +00:00
parent a766c0e9aa
commit 88f040e822
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B

View File

@ -25,8 +25,9 @@
package me.lucko.luckperms.common.extension; package me.lucko.luckperms.common.extension;
import com.google.gson.JsonElement; import com.google.gson.JsonObject;
import me.lucko.luckperms.common.loader.JarInJarClassLoader;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.util.gson.GsonProvider; import me.lucko.luckperms.common.util.gson.GsonProvider;
@ -42,6 +43,9 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
@ -116,6 +120,7 @@ public class SimpleExtensionManager implements ExtensionManager, AutoCloseable {
} }
String className; String className;
boolean useParentClassLoader = false;
try (JarFile jar = new JarFile(path.toFile())) { try (JarFile jar = new JarFile(path.toFile())) {
JarEntry extensionJarEntry = jar.getJarEntry("extension.json"); JarEntry extensionJarEntry = jar.getJarEntry("extension.json");
if (extensionJarEntry == null) { if (extensionJarEntry == null) {
@ -126,8 +131,11 @@ public class SimpleExtensionManager implements ExtensionManager, AutoCloseable {
throw new IllegalStateException("extension.json not present"); throw new IllegalStateException("extension.json not present");
} }
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
JsonElement parsed = GsonProvider.parser().parse(reader); JsonObject parsed = GsonProvider.parser().parse(reader).getAsJsonObject();
className = parsed.getAsJsonObject().get("class").getAsString(); className = parsed.get("class").getAsString();
if (parsed.has("useParentClassLoader")) {
useParentClassLoader = parsed.get("useParentClassLoader").getAsBoolean();
}
} }
} }
} }
@ -136,7 +144,15 @@ public class SimpleExtensionManager implements ExtensionManager, AutoCloseable {
throw new IllegalArgumentException("class is null"); throw new IllegalArgumentException("class is null");
} }
if (useParentClassLoader && getClass().getClassLoader() instanceof JarInJarClassLoader) {
try {
addJarToParentClasspath(path);
} catch (Exception e) {
throw new RuntimeException("Exception whilst classloading extension", e);
}
} else {
this.plugin.getBootstrap().getClassPathAppender().addJarToClasspath(path); this.plugin.getBootstrap().getClassPathAppender().addJarToClasspath(path);
}
Class<? extends Extension> extensionClass; Class<? extends Extension> extensionClass;
try { try {
@ -180,6 +196,18 @@ public class SimpleExtensionManager implements ExtensionManager, AutoCloseable {
return this.extensions.stream().map(e -> e.instance).collect(Collectors.toSet()); return this.extensions.stream().map(e -> e.instance).collect(Collectors.toSet());
} }
private static void addJarToParentClasspath(Path path) throws Exception {
ClassLoader parentClassLoader = SimpleExtensionManager.class.getClassLoader().getParent();
if (!(parentClassLoader instanceof URLClassLoader)) {
throw new RuntimeException("useParentClassLoader is true but parent is not a URLClassLoader");
}
Method addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
addUrlMethod.setAccessible(true);
addUrlMethod.invoke(parentClassLoader, path.toUri().toURL());
}
private static final class LoadedExtension { private static final class LoadedExtension {
private final Extension instance; private final Extension instance;
private final Path path; private final Path path;