This repository has been archived by the owner on Jan 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rewrite jimfs compat to work on OpenJ9, and in a cleaner way
Instead of resetting the FileSystemProvider list and changing the system classloader so that it is found properly when reloading, run ServiceLoader on our own classloader and add providers to the existing list (copying into an ArrayList to allow modifiability) Also refactored some code to make the intent clearer.
- Loading branch information
Showing
9 changed files
with
136 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
modGroup=link.infra.jumploader | ||
modVersion=1.0.11 | ||
modVersion=1.0.12 | ||
modBaseName=jumploader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 0 additions & 107 deletions
107
src/main/java/link/infra/jumploader/specialcases/FabricLoaderReflectionHack.java
This file was deleted.
Oops, something went wrong.
57 changes: 57 additions & 0 deletions
57
src/main/java/link/infra/jumploader/specialcases/FileSystemProviderAppender.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package link.infra.jumploader.specialcases; | ||
|
||
import link.infra.jumploader.resources.ParsedArguments; | ||
import link.infra.jumploader.util.ReflectionUtil; | ||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.Logger; | ||
|
||
import java.net.URL; | ||
import java.nio.file.spi.FileSystemProvider; | ||
import java.security.AccessController; | ||
import java.security.PrivilegedAction; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.ServiceLoader; | ||
|
||
public class FileSystemProviderAppender implements ReflectionHack { | ||
private final Logger LOGGER = LogManager.getLogger(); | ||
|
||
private void loadProvidersFromClassLoader(ClassLoader classLoader, List<FileSystemProvider> list) { | ||
ServiceLoader<FileSystemProvider> loader = ServiceLoader.load(FileSystemProvider.class, classLoader); | ||
|
||
for (FileSystemProvider provider: loader) { | ||
String scheme = provider.getScheme(); | ||
if (!scheme.equalsIgnoreCase("file")) { | ||
if (list.stream().noneMatch(p -> p.getScheme().equalsIgnoreCase(scheme))) { | ||
list.add(provider); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void applyReflectionHack(ClassLoader loadingClassloader) { | ||
// Ensure the existing providers are loaded first | ||
FileSystemProvider.installedProviders(); | ||
|
||
try { | ||
final Object lock = ReflectionUtil.reflectStaticField(FileSystemProvider.class, "lock"); | ||
//noinspection SynchronizationOnLocalVariableOrMethodParameter | ||
synchronized (lock) { | ||
// Load providers from the Jumploader classloader, and add them to the FileSystemProvider list | ||
ReflectionUtil.<List<FileSystemProvider>>transformStaticField(FileSystemProvider.class, "installedProviders", existingProviders -> { | ||
List<FileSystemProvider> newList = new ArrayList<>(existingProviders); | ||
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {loadProvidersFromClassLoader(loadingClassloader, newList); return null;}); | ||
return newList; | ||
}); | ||
} | ||
} catch (NoSuchFieldException | IllegalAccessException | ClassCastException e) { | ||
LOGGER.warn("Failed to fix FileSystemProvider loading, jar-in-jar may not work", e); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean shouldApply(List<URL> loadedJars, String mainClass, ParsedArguments gameArguments) { | ||
return true; | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
src/main/java/link/infra/jumploader/specialcases/JimfsReflectionHack.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package link.infra.jumploader.specialcases; | ||
|
||
import link.infra.jumploader.resources.ParsedArguments; | ||
import link.infra.jumploader.util.ReflectionUtil; | ||
import link.infra.jumploader.util.RegexUtil; | ||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.Logger; | ||
|
||
import java.lang.reflect.InvocationTargetException; | ||
import java.net.URL; | ||
import java.net.URLStreamHandler; | ||
import java.util.Hashtable; | ||
import java.util.List; | ||
import java.util.regex.Pattern; | ||
|
||
public class JimfsReflectionHack implements ReflectionHack { | ||
private final Logger LOGGER = LogManager.getLogger(); | ||
|
||
private static void injectJimfsHandler(ClassLoader classLoader) throws NoSuchFieldException, IllegalAccessException, ClassCastException, ClassNotFoundException, InstantiationException, NoSuchMethodException, InvocationTargetException { | ||
// Add the jimfs handler to the URL handlers field, because Class.forName by default uses the classloader that loaded the calling class (in this case the system classloader, so we have to do it manually) | ||
Hashtable<String, URLStreamHandler> handlers = ReflectionUtil.reflectStaticField(URL.class, "handlers"); | ||
handlers.putIfAbsent("jimfs", (URLStreamHandler) Class.forName("com.google.common.jimfs.Handler", true, classLoader).getDeclaredConstructor().newInstance()); | ||
} | ||
|
||
@Override | ||
public void applyReflectionHack(ClassLoader loadingClassloader) { | ||
// Jimfs requires some funky hacks to load under a custom classloader, Java protocol handlers don't handle custom classloaders very well | ||
// See also FileSystemProviderAppender | ||
try { | ||
JimfsReflectionHack.injectJimfsHandler(loadingClassloader); | ||
} catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException | InstantiationException | ClassCastException | NoSuchMethodException | InvocationTargetException e) { | ||
LOGGER.warn("Failed to fix jimfs loading, jar-in-jar may not work", e); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean shouldApply(List<URL> loadedJars, String mainClass, ParsedArguments gameArguments) { | ||
return RegexUtil.patternMatchesJars(Pattern.compile("jimfs-(.+)\\.jar$"), loadedJars); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
src/main/java/link/infra/jumploader/util/ReflectionUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package link.infra.jumploader.util; | ||
|
||
import java.lang.reflect.Field; | ||
import java.util.function.Function; | ||
|
||
public class ReflectionUtil { | ||
@SuppressWarnings("unchecked") | ||
public static <T> T reflectField(Object destObj, String name) throws NoSuchFieldException, IllegalAccessException, ClassCastException { | ||
Field field = destObj.getClass().getDeclaredField(name); | ||
field.setAccessible(true); | ||
return (T) field.get(destObj); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
public static <T> T reflectStaticField(Class<?> destClass, String name) throws NoSuchFieldException, IllegalAccessException, ClassCastException { | ||
Field field = destClass.getDeclaredField(name); | ||
field.setAccessible(true); | ||
return (T) field.get(null); | ||
} | ||
|
||
@SuppressWarnings({"unchecked", "UnusedReturnValue"}) | ||
public static <T> T transformStaticField(Class<?> destClass, String name, Function<T, T> transformer) throws NoSuchFieldException, IllegalAccessException, ClassCastException { | ||
Field field = destClass.getDeclaredField(name); | ||
field.setAccessible(true); | ||
T value = transformer.apply((T) field.get(null)); | ||
field.set(null, value); | ||
return value; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters