From 52b6da17599dd0092b96b7c42204424ce6f79ebb Mon Sep 17 00:00:00 2001 From: David Quintana Date: Fri, 14 Dec 2018 00:33:35 +0100 Subject: [PATCH] Fix classloading issues in userdev (and possibly also for things like tests within forgedev) (#5275) --- build.gradle | 1 + .../fml/ModLoadingClassLoader.java | 15 ++++- .../userdev/ClasspathLocator.java | 59 +++++++++++++------ 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/build.gradle b/build.gradle index fd685e19f..7098dc401 100644 --- a/build.gradle +++ b/build.gradle @@ -460,6 +460,7 @@ project(':forge') { def libs = [:] def json = [ _comment_: launcherJson.comment, + spec: 0, profile: project.name, version: launcherJson.id, json: '/version.json', diff --git a/src/main/java/net/minecraftforge/fml/ModLoadingClassLoader.java b/src/main/java/net/minecraftforge/fml/ModLoadingClassLoader.java index 2eedaa8ae..62400ffdf 100644 --- a/src/main/java/net/minecraftforge/fml/ModLoadingClassLoader.java +++ b/src/main/java/net/minecraftforge/fml/ModLoadingClassLoader.java @@ -33,7 +33,6 @@ import static net.minecraftforge.fml.Logging.LOADING; public class ModLoadingClassLoader extends SecureClassLoader { - private static final Logger LOGGER = LogManager.getLogger(); static { @@ -50,6 +49,18 @@ public class ModLoadingClassLoader extends SecureClassLoader return super.getResource(name); } + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException + { + final String className = name.replace('.', '/').concat(".class"); + final Path classResource = FMLLoader.getLoadingModList().findResource(className); + if (classResource != null) + { + return findClass(name); + } + return super.loadClass(name, resolve); + } + @Override protected Class findClass(String name) throws ClassNotFoundException { @@ -65,7 +76,7 @@ public class ModLoadingClassLoader extends SecureClassLoader { throw new ClassNotFoundException("Failed to load class file " + classResource + " for "+ className, e); } - } else { + } else if(getParent() != null) { getParent().loadClass(name); } throw new ClassNotFoundException("Failed to find class file "+ className); diff --git a/src/userdev/java/net/minecraftforge/userdev/ClasspathLocator.java b/src/userdev/java/net/minecraftforge/userdev/ClasspathLocator.java index 7f16338dd..755199c5c 100644 --- a/src/userdev/java/net/minecraftforge/userdev/ClasspathLocator.java +++ b/src/userdev/java/net/minecraftforge/userdev/ClasspathLocator.java @@ -20,6 +20,7 @@ package net.minecraftforge.userdev; import com.google.common.collect.Sets; +import com.google.common.collect.Streams; import net.minecraftforge.fml.loading.moddiscovery.IModLocator; import net.minecraftforge.fml.loading.moddiscovery.ModFile; import org.apache.logging.log4j.LogManager; @@ -27,10 +28,16 @@ import org.apache.logging.log4j.Logger; import java.io.File; import java.io.IOException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.UserPrincipalLookupService; +import java.nio.file.spi.FileSystemProvider; import java.util.*; import java.util.function.Consumer; import java.util.jar.Manifest; @@ -88,7 +95,16 @@ public class ClasspathLocator implements IModLocator if (path.length < 1) { throw new IllegalArgumentException("Missing path"); } - return modFile.getFilePath().resolve(modFile.getFilePath().getFileSystem().getPath(path[0], Arrays.copyOfRange(path, 1, path.length))); + + Path filePath = modFile.getFilePath(); + Path classesRoot = getClassesPath(filePath); + String[] tail = Arrays.copyOfRange(path, 1, path.length); + Path classPath = classesRoot.resolve(classesRoot.getFileSystem().getPath(path[0], tail)); + if(Files.exists(classPath)) + { + return classPath; + } + return filePath.resolve(filePath.getFileSystem().getPath(path[0], tail)); } @Override @@ -96,22 +112,7 @@ public class ClasspathLocator implements IModLocator LOGGER.debug(SCAN,"Scanning classpath"); Path filePath = modFile.getFilePath(); - - Path scanPath = filePath; - - // Hack 1: When running from within intellij, we get - // "out/production/resources" + "out/production/classes" - if(filePath.getNameCount() >= 1 && filePath.getName(filePath.getNameCount()-1).toString().equals("resources")) - { - scanPath = filePath.getParent().resolve("classes"); - } - // Hack 2: When running from gradle, we get - // "build/resources/" + "build/classes//" - else if(filePath.getNameCount() >= 2 && filePath.getName(filePath.getNameCount()-2).toString().equals("resources")) - { - // We'll scan all the subdirectories for languages and sourcesets, hopefully that works... - scanPath = filePath.getParent().getParent().resolve("classes"); - } + Path scanPath = getClassesPath(filePath); try (Stream files = Files.find(scanPath, Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) { files.forEach(pathConsumer); @@ -121,6 +122,26 @@ public class ClasspathLocator implements IModLocator LOGGER.debug(SCAN,"Classpath scan complete"); } + private Path getClassesPath(Path filePath) + { + Path classesPath = filePath; + + // Hack 1: When running from within intellij, we get + // "out/production/resources" + "out/production/classes" + if(filePath.getNameCount() >= 1 && filePath.getName(filePath.getNameCount()-1).toString().equals("resources")) + { + classesPath = filePath.getParent().resolve("classes"); + } + // Hack 2: When running from gradle, we get + // "build/resources/" + "build/classes//" + else if(filePath.getNameCount() >= 2 && filePath.getName(filePath.getNameCount()-2).toString().equals("resources")) + { + // We'll scan all the subdirectories for languages and sourcesets, hopefully that works... + classesPath = filePath.getParent().getParent().resolve("classes"); + } + return classesPath; + } + @Override public String toString() {