mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-29 23:40:00 +00:00
Native provider loading
- Native provider classes load from the provider jars before the plugin class loader - Another plugin bundling VolmLib natives no longer supplies Iris native capabilities on Spigot - Tests cover provider jar classes taking precedence over the plugin loader
This commit is contained in:
1 parent
21ab5baf27
commit
c700138b66
2 files changed
+61
-2
No files matched your search
@@ -65,8 +65,7 @@ public final class NativeRuntimeLibraries {
|
|||||||
public URLClassLoader openProviderLoader(Path downloads) {
|
public URLClassLoader openProviderLoader(Path downloads) {
|
||||||
try {
|
try {
|
||||||
List<URL> urls = providerUrls(downloads, NativeRuntimeLibraries.class.getClassLoader());
|
List<URL> urls = providerUrls(downloads, NativeRuntimeLibraries.class.getClassLoader());
|
||||||
URLClassLoader loader = new URLClassLoader("Iris native providers", urls.toArray(URL[]::new),
|
URLClassLoader loader = providerLoader(urls.toArray(URL[]::new), NativeAdapters.class.getClassLoader());
|
||||||
NativeAdapters.class.getClassLoader());
|
|
||||||
NativeAdapters.registerProviderLoader(loader);
|
NativeAdapters.registerProviderLoader(loader);
|
||||||
return loader;
|
return loader;
|
||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
@@ -74,6 +73,10 @@ public final class NativeRuntimeLibraries {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static URLClassLoader providerLoader(URL[] urls, ClassLoader parent) {
|
||||||
|
return new ProviderClassLoader(urls, parent);
|
||||||
|
}
|
||||||
|
|
||||||
List<URL> providerUrls(Path downloads, ClassLoader resources) throws IOException {
|
List<URL> providerUrls(Path downloads, ClassLoader resources) throws IOException {
|
||||||
List<URL> urls = new ArrayList<>(providers.size());
|
List<URL> urls = new ArrayList<>(providers.size());
|
||||||
for (Provider provider : providers) {
|
for (Provider provider : providers) {
|
||||||
@@ -123,4 +126,28 @@ public final class NativeRuntimeLibraries {
|
|||||||
|
|
||||||
private record Provider(String module, String version, String sha256) {
|
private record Provider(String module, String version, String sha256) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class ProviderClassLoader extends URLClassLoader {
|
||||||
|
private ProviderClassLoader(URL[] urls, ClassLoader parent) {
|
||||||
|
super("Iris native providers", urls, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||||
|
synchronized (getClassLoadingLock(name)) {
|
||||||
|
Class<?> loaded = findLoadedClass(name);
|
||||||
|
if (loaded == null) {
|
||||||
|
try {
|
||||||
|
loaded = findClass(name);
|
||||||
|
} catch (ClassNotFoundException absent) {
|
||||||
|
return super.loadClass(name, resolve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resolve) {
|
||||||
|
resolveClass(loaded);
|
||||||
|
}
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,8 @@ package art.arcane.iris.platform.bootstrap;
|
|||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -25,6 +27,7 @@ import java.util.stream.Stream;
|
|||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
@@ -41,6 +44,20 @@ public class NativeRuntimeLibrariesTest {
|
|||||||
assertThrows(IllegalStateException.class, () -> NativeRuntimeLibraries.from(fixture.manifest(), "26.2.0"));
|
assertThrows(IllegalStateException.class, () -> NativeRuntimeLibraries.from(fixture.manifest(), "26.2.0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void providerClassesLoadFromTheProviderJarBeforeThePluginLoader() throws Exception {
|
||||||
|
String implementation = "art/arcane/volmlib/nativelib/v26_2_R1/Probe";
|
||||||
|
String api = "art/arcane/volmlib/nativelib/Api";
|
||||||
|
Path plugin = classJar("plugin.jar", implementation, api);
|
||||||
|
Path provider = classJar("provider.jar", implementation);
|
||||||
|
try (URLClassLoader parent = new URLClassLoader(new URL[]{plugin.toUri().toURL()}, null);
|
||||||
|
URLClassLoader loader = NativeRuntimeLibraries.providerLoader(new URL[]{provider.toUri().toURL()}, parent)) {
|
||||||
|
assertSame(loader, loader.loadClass(implementation.replace('/', '.')).getClassLoader());
|
||||||
|
assertSame(parent, loader.loadClass(api.replace('/', '.')).getClassLoader());
|
||||||
|
assertSame(String.class, loader.loadClass("java.lang.String"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void rejectsMinecraftVersionsWithoutProvider() throws Exception {
|
public void rejectsMinecraftVersionsWithoutProvider() throws Exception {
|
||||||
EmbeddedFixture fixture = embeddedFixture();
|
EmbeddedFixture fixture = embeddedFixture();
|
||||||
@@ -156,6 +173,21 @@ public class NativeRuntimeLibrariesTest {
|
|||||||
return new EmbeddedFixture(properties, resources);
|
return new EmbeddedFixture(properties, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Path classJar(String name, String... classes) throws IOException {
|
||||||
|
Path jar = temporary.newFolder().toPath().resolve(name);
|
||||||
|
try (JarOutputStream output = new JarOutputStream(Files.newOutputStream(jar))) {
|
||||||
|
for (String type : classes) {
|
||||||
|
ClassWriter writer = new ClassWriter(0);
|
||||||
|
writer.visit(Opcodes.V17, Opcodes.ACC_PUBLIC, type, null, "java/lang/Object", null);
|
||||||
|
writer.visitEnd();
|
||||||
|
output.putNextEntry(new JarEntry(type + ".class"));
|
||||||
|
output.write(writer.toByteArray());
|
||||||
|
output.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jar;
|
||||||
|
}
|
||||||
|
|
||||||
private static void assertNoFailedExtract(Path downloads) throws IOException {
|
private static void assertNoFailedExtract(Path downloads) throws IOException {
|
||||||
try (Stream<Path> files = Files.walk(downloads)) {
|
try (Stream<Path> files = Files.walk(downloads)) {
|
||||||
assertFalse(files.anyMatch(path -> Files.isRegularFile(path)
|
assertFalse(files.anyMatch(path -> Files.isRegularFile(path)
|
||||||
|
|||||||
Reference in new issue
Block a user