Fix classloading issues in userdev (and possibly also for things like tests within forgedev) (#5275)

This commit is contained in:
David Quintana 2018-12-14 00:33:35 +01:00 committed by LexManos
parent f13465012b
commit 52b6da1759
3 changed files with 54 additions and 21 deletions

View file

@ -460,6 +460,7 @@ project(':forge') {
def libs = [:]
def json = [
_comment_: launcherJson.comment,
spec: 0,
profile: project.name,
version: launcherJson.id,
json: '/version.json',

View file

@ -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);

View file

@ -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/<sourceset>" + "build/classes/<language>/<sourceset>"
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<Path> 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/<sourceset>" + "build/classes/<language>/<sourceset>"
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()
{