diff --git a/Common/loader-utils/src/main/java/dev/brighten/antivpn/loader/JarInJarClassLoader.java b/Common/loader-utils/src/main/java/dev/brighten/antivpn/loader/JarInJarClassLoader.java
index 3d1ccb4..27958bc 100644
--- a/Common/loader-utils/src/main/java/dev/brighten/antivpn/loader/JarInJarClassLoader.java
+++ b/Common/loader-utils/src/main/java/dev/brighten/antivpn/loader/JarInJarClassLoader.java
@@ -27,6 +27,10 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.Set;
/**
* Classloader that can load a jar from within another jar file.
@@ -38,6 +42,26 @@ import java.util.Arrays;
* by the loading code & this classloader.
*/
public class JarInJarClassLoader extends URLClassLoader {
+ private static final String[] PARENT_FIRST_PACKAGES = {
+ "java.",
+ "javax.",
+ "jdk.",
+ "sun.",
+ "com.sun.",
+ "org.w3c.",
+ "org.xml.",
+ "org.slf4j.",
+ "com.google.inject.",
+ "javax.inject.",
+ "com.velocitypowered.",
+ "org.bukkit.",
+ "net.md_5.bungee.",
+ "org.spongepowered.",
+ "org.bstats.",
+ "dev.brighten.antivpn.velocity.org.bstats.",
+ "dev.brighten.antivpn.loader."
+ };
+
static {
ClassLoader.registerAsParallelCapable();
}
@@ -59,6 +83,74 @@ public class JarInJarClassLoader extends URLClassLoader {
addURL(url);
}
+ @Override
+ protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ synchronized (getClassLoadingLock(name)) {
+ Class> loadedClass = findLoadedClass(name);
+ if (loadedClass == null) {
+ loadedClass = shouldLoadParentFirst(name) ? loadParentThenChild(name) : loadChildThenParent(name);
+ }
+
+ if (resolve) {
+ resolveClass(loadedClass);
+ }
+
+ return loadedClass;
+ }
+ }
+
+ @Override
+ public URL getResource(String name) {
+ URL resource = findResource(name);
+ if (resource != null) {
+ return resource;
+ }
+ return super.getResource(name);
+ }
+
+ @Override
+ public Enumeration getResources(String name) throws IOException {
+ Set resources = new LinkedHashSet<>();
+ Enumeration childResources = findResources(name);
+ while (childResources.hasMoreElements()) {
+ resources.add(childResources.nextElement());
+ }
+
+ Enumeration parentResources = getParent() == null
+ ? ClassLoader.getSystemResources(name)
+ : getParent().getResources(name);
+ while (parentResources.hasMoreElements()) {
+ resources.add(parentResources.nextElement());
+ }
+
+ return Collections.enumeration(resources);
+ }
+
+ private Class> loadChildThenParent(String name) throws ClassNotFoundException {
+ try {
+ return findClass(name);
+ } catch (ClassNotFoundException ignored) {
+ return super.loadClass(name, false);
+ }
+ }
+
+ private Class> loadParentThenChild(String name) throws ClassNotFoundException {
+ try {
+ return super.loadClass(name, false);
+ } catch (ClassNotFoundException ignored) {
+ return findClass(name);
+ }
+ }
+
+ private static boolean shouldLoadParentFirst(String className) {
+ for (String prefix : PARENT_FIRST_PACKAGES) {
+ if (className.startsWith(prefix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public void deleteJarResource() {
URL[] urls = getURLs();
if (urls.length == 0) {
diff --git a/Velocity/VelocityLoader/src/main/java/dev/brighten/antivpn/velocity/VelocityPluginLoader.java b/Velocity/VelocityLoader/src/main/java/dev/brighten/antivpn/velocity/VelocityPluginLoader.java
index 9bf68ba..bf9885b 100644
--- a/Velocity/VelocityLoader/src/main/java/dev/brighten/antivpn/velocity/VelocityPluginLoader.java
+++ b/Velocity/VelocityLoader/src/main/java/dev/brighten/antivpn/velocity/VelocityPluginLoader.java
@@ -40,6 +40,7 @@ public class VelocityPluginLoader {
private static final String BOOTSTRAP_CLASS = "dev.brighten.antivpn.velocity.VelocityPlugin";
private final LoaderBootstrap plugin;
+ private final ClassLoader pluginClassLoader;
@Inject
public VelocityPluginLoader(ProxyServer server, Logger logger, @DataDirectory Path path, Metrics.Factory metricsFactory) {
@@ -50,18 +51,30 @@ public class VelocityPluginLoader {
instances.put(String.class, metricsFactory);
instances.put(LoaderBootstrap.class, this);
JarInJarClassLoader loader = new JarInJarClassLoader(getClass().getClassLoader(), JAR_NAME, SOURCE_NAME);
+ this.pluginClassLoader = loader;
this.plugin = loader.instantiatePlugin(BOOTSTRAP_CLASS, Map.class, instances);
- plugin.onLoad(path.toFile());
+ runWithPluginClassLoader(() -> plugin.onLoad(path.toFile()));
}
@Subscribe
public void onInit(ProxyInitializeEvent event) {
- plugin.onEnable();
+ runWithPluginClassLoader(plugin::onEnable);
}
@Subscribe
public void onDisable(ProxyShutdownEvent event) {
- plugin.onDisable();
+ runWithPluginClassLoader(plugin::onDisable);
+ }
+
+ private void runWithPluginClassLoader(Runnable action) {
+ Thread thread = Thread.currentThread();
+ ClassLoader previousClassLoader = thread.getContextClassLoader();
+ thread.setContextClassLoader(pluginClassLoader);
+ try {
+ action.run();
+ } finally {
+ thread.setContextClassLoader(previousClassLoader);
+ }
}
}