diff --git a/HMCL/build.gradle b/HMCL/build.gradle index 7387352f5..73a7f8693 100644 --- a/HMCL/build.gradle +++ b/HMCL/build.gradle @@ -81,7 +81,20 @@ def repack(File file) { new JarOutputStream(file.newOutputStream()).withCloseable { unpacker.unpack(new ByteArrayInputStream(packed.toByteArray()), it) } } +sourceSets { + java11 { + java { + srcDirs = ['src/main/java11'] + } + } +} + jar { + into('META-INF/versions/11') { + from sourceSets.java11.output + exclude "java/**" + exclude "jdk/**" + } manifest { attributes 'Created-By': 'Copyright(c) 2013-2020 huangyuhui.', 'Main-Class': mainClassName, @@ -99,6 +112,7 @@ jar { 'javafx.graphics/com.sun.javafx.stage' ].join(" "), 'Add-Exports': [ + 'java.base/jdk.internal.loader', 'javafx.controls/com.sun.javafx.scene.control.behavior', 'javafx.controls/javafx.scene.control.skin', 'javafx.controls/com.sun.javafx.scene.control', diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/Main.java b/HMCL/src/main/java/org/jackhuang/hmcl/Main.java index ced378fe6..ba9f81842 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/Main.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/Main.java @@ -19,7 +19,6 @@ package org.jackhuang.hmcl; import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.SelfDependencyPatcher; -import org.jackhuang.hmcl.util.VMUtils; import javax.net.ssl.*; import javax.swing.*; @@ -59,8 +58,6 @@ public final class Main { Logging.start(Metadata.HMCL_DIRECTORY.resolve("logs")); - VMUtils.patch(); - checkJavaFX(); // Fix title bar not displaying in GTK systems diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/JavaFXPatcher.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/JavaFXPatcher.java new file mode 100644 index 000000000..e06fa87f5 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/JavaFXPatcher.java @@ -0,0 +1,9 @@ +package org.jackhuang.hmcl.util; + +import java.nio.file.Path; + +public class JavaFXPatcher { + public static void patch(Path... jarPaths) { + // Nothing to do with Java 8 + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/SelfDependencyPatcher.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/SelfDependencyPatcher.java index 8759146b1..14db415c1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/SelfDependencyPatcher.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/SelfDependencyPatcher.java @@ -6,13 +6,13 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem; import javax.swing.*; import java.awt.*; +import java.io.File; import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.List; import java.util.*; @@ -34,53 +34,12 @@ import static org.jackhuang.hmcl.util.platform.JavaVersion.CURRENT_JAVA; */ public class SelfDependencyPatcher { private static final Path DEPENDENCIES_DIR_PATH = HMCL_DIRECTORY.resolve("dependencies"); - private static final Map> JFX_DEPENDENCIES = new LinkedHashMap>(5, 1F) { + private static final String DEFAULT_JFX_VERSION = "16"; + private static final Map JFX_DEPENDENCIES_ = new HashMap() { { - put(15, Arrays.asList( - jfxUrl("swing", "15.0.1"), - jfxUrl("media", "15.0.1"), - jfxUrl("fxml", "15.0.1"), - jfxUrl("web", "15.0.1"), - jfxUrl("controls", "15.0.1"), - jfxUrl("graphics", "15.0.1"), - jfxUrl("base", "15.0.1") - )); - put(14, Arrays.asList( - jfxUrl("swing", "14.0.2"), - jfxUrl("media", "14.0.2"), - jfxUrl("fxml", "14.0.2"), - jfxUrl("web", "14.0.2"), - jfxUrl("controls", "14.0.2"), - jfxUrl("graphics", "14.0.2"), - jfxUrl("base", "14.0.2") - )); - put(13, Arrays.asList( - jfxUrl("swing", "13.0.2"), - jfxUrl("media", "13.0.2"), - jfxUrl("fxml", "13.0.2"), - jfxUrl("web", "13.0.2"), - jfxUrl("controls", "13.0.2"), - jfxUrl("graphics", "13.0.2"), - jfxUrl("base", "13.0.2") - )); - put(12, Arrays.asList( - jfxUrl("swing", "12.0.2"), - jfxUrl("media", "12.0.2"), - jfxUrl("fxml", "12.0.2"), - jfxUrl("web", "12.0.2"), - jfxUrl("controls", "12.0.2"), - jfxUrl("graphics", "12.0.2"), - jfxUrl("base", "12.0.2") - )); - put(11, Arrays.asList( - jfxUrl("swing", "11.0.2"), - jfxUrl("media", "11.0.2"), - jfxUrl("fxml", "11.0.2"), - jfxUrl("web", "11.0.2"), - jfxUrl("controls", "11.0.2"), - jfxUrl("graphics", "11.0.2"), - jfxUrl("base", "11.0.2") - )); + for (String url : new String [] { jfxUrl("base"), jfxUrl("controls"), jfxUrl("fxml"), jfxUrl("graphics"), jfxUrl("media"), jfxUrl("swing"), jfxUrl("web") }) { + put(getFileName(url), url); + } } }; @@ -151,32 +110,9 @@ public class SelfDependencyPatcher { */ private static void loadFromCache() throws IOException, ReflectiveOperationException { LOG.info(" - Loading dependencies..."); - // Get Jar URLs - List jarUrls = new ArrayList<>(); - Files.walk(DEPENDENCIES_DIR_PATH).forEach(path -> { - try { - jarUrls.add(path.toUri().toURL()); - } catch(MalformedURLException ex) { - LOG.log(Level.WARNING, "Failed to convert '" + path.toFile().getAbsolutePath() + "' to URL", ex); - } - }); - // Fetch UCP of application's ClassLoader - // - ((ClassLoaders.AppClassLoader) ClassLoaders.appClassLoader()).ucp - Class clsClassLoaders = Class.forName("jdk.internal.loader.ClassLoaders"); - Object appClassLoader = clsClassLoaders.getDeclaredMethod("appClassLoader").invoke(null); - Class ucpOwner = appClassLoader.getClass(); - // Field removed in 16, but still exists in parent class "BuiltinClassLoader" - if (CURRENT_JAVA.getParsedVersion() >= 16) - ucpOwner = ucpOwner.getSuperclass(); - Field fieldUCP = ucpOwner.getDeclaredField("ucp"); - fieldUCP.setAccessible(true); - Object ucp = fieldUCP.get(appClassLoader); - Class clsUCP = ucp.getClass(); - Method addURL = clsUCP.getDeclaredMethod("addURL", URL.class); - addURL.setAccessible(true); - // Add each jar. - for(URL url : jarUrls) - addURL.invoke(ucp, url); + List jarPaths = new ArrayList<>(); + Files.walk(DEPENDENCIES_DIR_PATH).filter(p -> JFX_DEPENDENCIES_.containsKey(p.getFileName().toString())).forEach(jarPaths::add); + JavaFXPatcher.patch(jarPaths.toArray(new Path[0])); } /** @@ -194,9 +130,9 @@ public class SelfDependencyPatcher { ForkJoinTask task = ForkJoinPool.commonPool().submit(() -> { // Download each dependency - List dependencies = getLatestDependencies(); - for (int i = 0; i < dependencies.size(); i++) { - String dependencyUrlPath = dependencies.get(i); + Collection dependencies = JFX_DEPENDENCIES_.values(); + int i = 0; + for (String dependencyUrlPath : dependencies) { URL depURL = new URL(dependencyUrlPath); Path dependencyFilePath = DEPENDENCIES_DIR_PATH.resolve(getFileName(dependencyUrlPath)); int finalI = i; @@ -204,12 +140,9 @@ public class SelfDependencyPatcher { dialog.setStatus(dependencyUrlPath); dialog.setProgress(finalI, dependencies.size()); }); - String expectedHash = NetworkUtils.doGet(NetworkUtils.toURL(dependencyUrlPath + ".sha1")); Files.copy(depURL.openStream(), dependencyFilePath, StandardCopyOption.REPLACE_EXISTING); - String actualHash = Hex.encodeHex(DigestUtils.digest("SHA-1", dependencyFilePath)); - if (!expectedHash.equalsIgnoreCase(actualHash)) { - throw new ChecksumMismatchException("SHA-1", expectedHash, actualHash); - } + checksum(dependencyFilePath, dependencyUrlPath); + i++; } return null; @@ -224,10 +157,31 @@ public class SelfDependencyPatcher { * @return {@code true} when the dependencies directory has files in it. */ private static boolean hasCachedDependencies() { - String[] files = DEPENDENCIES_DIR_PATH.toFile().list(); - if (files == null) + if (!Files.isDirectory(DEPENDENCIES_DIR_PATH)) return false; - return files.length >= getLatestDependencies().size(); + + for (String name : JFX_DEPENDENCIES_.keySet()) { + Path dependencyFilePath = DEPENDENCIES_DIR_PATH.resolve(name); + if (!Files.exists(dependencyFilePath)) + return false; + + try { + checksum(dependencyFilePath, JFX_DEPENDENCIES_.get(name)); + } catch (ChecksumMismatchException e) { + return false; + } catch (IOException ignored) { + // Ignore other situations + } + } + return true; + } + + private static void checksum(Path dependencyFilePath, String dependencyUrlPath) throws IOException { + String expectedHash = NetworkUtils.doGet(NetworkUtils.toURL(dependencyUrlPath + ".sha1")); + String actualHash = Hex.encodeHex(DigestUtils.digest("SHA-1", dependencyFilePath)); + if (!expectedHash.equalsIgnoreCase(actualHash)) { + throw new ChecksumMismatchException("SHA-1", expectedHash, actualHash); + } } /** @@ -242,6 +196,10 @@ public class SelfDependencyPatcher { * @param component Name of the component. * @return Formed URL for the component. */ + private static String jfxUrl(String component) { + return jfxUrl(component, DEFAULT_JFX_VERSION); + } + private static String jfxUrl(String component, String version) { // https://repo1.maven.org/maven2/org/openjfx/javafx-%s/%s/javafx-%s-%s-%s.jar return String.format("https://maven.aliyun.com/repository/central/org/openjfx/javafx-%s/%s/javafx-%s-%s-%s.jar", @@ -250,31 +208,6 @@ public class SelfDependencyPatcher { // component, version, component, version, getMvnName()); } - /** - * @return Latest JavaFX supported version for. - */ - private static int getLatestSupportedJfxVersion() { - int version = CURRENT_JAVA.getParsedVersion(); - while (version >= 11) { - List dependencies = JFX_DEPENDENCIES.get(version); - if (dependencies != null) - return version; - version--; - } - throw new AssertionError("Failed to get latest supported JFX version"); - } - - /** - * @return JavaFX dependencies list for the current VM version. - */ - private static List getLatestDependencies() { - int version = getLatestSupportedJfxVersion(); - if (version >= 11) { - return JFX_DEPENDENCIES.get(version); - } - throw new AssertionError("Failed to get latest JFX artifact urls"); - } - private static String getMvnName() { switch (OperatingSystem.CURRENT_OS) { case LINUX: diff --git a/HMCLCore/src/main/java/java/lang/module/ModuleFinder.java b/HMCL/src/main/java11/java/lang/module/ModuleFinder.java similarity index 79% rename from HMCLCore/src/main/java/java/lang/module/ModuleFinder.java rename to HMCL/src/main/java11/java/lang/module/ModuleFinder.java index f5a52745a..4255d2377 100644 --- a/HMCLCore/src/main/java/java/lang/module/ModuleFinder.java +++ b/HMCL/src/main/java11/java/lang/module/ModuleFinder.java @@ -1,5 +1,6 @@ package java.lang.module; +import java.nio.file.Path; import java.util.Set; /** @@ -9,9 +10,9 @@ import java.util.Set; */ public interface ModuleFinder { //CHECKSTYLE:OFF - static ModuleFinder ofSystem() { + static ModuleFinder of(Path... entries) { throw new UnsupportedOperationException(); } Set findAll(); //CHECKSTYLE:ON -} +} \ No newline at end of file diff --git a/HMCL/src/main/java11/java/lang/module/ModuleReference.java b/HMCL/src/main/java11/java/lang/module/ModuleReference.java new file mode 100644 index 000000000..e8c9d1a1f --- /dev/null +++ b/HMCL/src/main/java11/java/lang/module/ModuleReference.java @@ -0,0 +1,4 @@ +package java.lang.module; + +public class ModuleReference { +} diff --git a/HMCL/src/main/java11/jdk/internal/loader/BuiltinClassLoader.java b/HMCL/src/main/java11/jdk/internal/loader/BuiltinClassLoader.java new file mode 100644 index 000000000..efb629862 --- /dev/null +++ b/HMCL/src/main/java11/jdk/internal/loader/BuiltinClassLoader.java @@ -0,0 +1,14 @@ +package jdk.internal.loader; + +import java.lang.module.ModuleReference; + +/** + * Dummy java compatibility class + * + * @author xxDark + */ +public class BuiltinClassLoader extends ClassLoader { + public void loadModule(ModuleReference mref) { + throw new UnsupportedOperationException(); + } +} diff --git a/HMCL/src/main/java11/org/jackhuang/hmcl/util/JavaFXPatcher.java b/HMCL/src/main/java11/org/jackhuang/hmcl/util/JavaFXPatcher.java new file mode 100644 index 000000000..15274219d --- /dev/null +++ b/HMCL/src/main/java11/org/jackhuang/hmcl/util/JavaFXPatcher.java @@ -0,0 +1,15 @@ +package org.jackhuang.hmcl.util; + +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.nio.file.Path; + +import jdk.internal.loader.BuiltinClassLoader; + +public class JavaFXPatcher { + public static void patch(Path... jarPaths) { + for (ModuleReference mref : ModuleFinder.of(jarPaths).findAll()) { + ((BuiltinClassLoader) ClassLoader.getSystemClassLoader()).loadModule(mref); + } + } +} diff --git a/HMCLCore/src/main/java/java/lang/Module.java b/HMCLCore/src/main/java/java/lang/Module.java deleted file mode 100644 index c4180f357..000000000 --- a/HMCLCore/src/main/java/java/lang/Module.java +++ /dev/null @@ -1,16 +0,0 @@ -package java.lang; - -import java.util.Set; - -/** - * Dummy java compatibility class - * - * @author Matt - */ -public abstract class Module { - - //CHECKSTYLE:OFF - public ModuleLayer getLayer() { throw new UnsupportedOperationException(); } - public Set getPackages() { throw new UnsupportedOperationException(); } - //CHECKSTYLE:ON -} diff --git a/HMCLCore/src/main/java/java/lang/ModuleLayer.java b/HMCLCore/src/main/java/java/lang/ModuleLayer.java deleted file mode 100644 index c4e418033..000000000 --- a/HMCLCore/src/main/java/java/lang/ModuleLayer.java +++ /dev/null @@ -1,20 +0,0 @@ -package java.lang; - -import java.util.Set; - -/** - * Dummy java compatibility class - * - * @author xxDark - */ -public abstract class ModuleLayer { - - //CHECKSTYLE:OFF - public Set modules() { - throw new UnsupportedOperationException(); - } - public static ModuleLayer boot() { - throw new UnsupportedOperationException(); - } - //CHECKSTYLE:ON -} diff --git a/HMCLCore/src/main/java/java/lang/module/ModuleReader.java b/HMCLCore/src/main/java/java/lang/module/ModuleReader.java deleted file mode 100644 index 09fe4ab5d..000000000 --- a/HMCLCore/src/main/java/java/lang/module/ModuleReader.java +++ /dev/null @@ -1,18 +0,0 @@ -package java.lang.module; - -import java.io.Closeable; -import java.io.IOException; -import java.util.stream.Stream; - -/** - * Dummy java compatibility class - * - * @author xxDark - */ -public interface ModuleReader extends Closeable { - //CHECKSTYLE:OFF - Stream list() throws IOException; - @Override - void close() throws IOException; - //CHECKSTYLE:ON -} diff --git a/HMCLCore/src/main/java/java/lang/module/ModuleReference.java b/HMCLCore/src/main/java/java/lang/module/ModuleReference.java deleted file mode 100644 index 0d8007eb8..000000000 --- a/HMCLCore/src/main/java/java/lang/module/ModuleReference.java +++ /dev/null @@ -1,14 +0,0 @@ -package java.lang.module; - -import java.io.IOException; - -/** - * Dummy java compatibility class - * - * @author xxDark - */ -public abstract class ModuleReference { - //CHECKSTYLE:OFF - public abstract ModuleReader open() throws IOException; - //CHECKSTYLE:ON -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ClassUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ClassUtils.java deleted file mode 100644 index 1b4a67f6a..000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/ClassUtils.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.jackhuang.hmcl.util; - -/** - * Utilities for dealing with class-file loading/parsing. - * - * @author Matt - */ -public class ClassUtils { - /** - * The offset from which a version and the version constant value is. For example, Java 8 is 52 (44 + 8). - */ - public static final int VERSION_OFFSET = 44; -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Java9Util.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Java9Util.java deleted file mode 100644 index b3a43b4fe..000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Java9Util.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.jackhuang.hmcl.util; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; -import java.lang.reflect.Field; - -/** - * Package-private util to deal with modules. - * - * @author xxDark - */ -final class Java9Util { - - private static final MethodHandle CLASS_MODULE; - private static final MethodHandle CLASS_LOADER_MDOULE; - - /** - * Deny all constructions. - */ - private Java9Util() { - } - - /** - * @param klass {@link Class} to get module from. - * @return {@link Module} of the class. - */ - static Module getClassModule(Class klass) { - try { - return (Module) CLASS_MODULE.invokeExact(klass); - } catch (Throwable t) { - // That should never happen. - throw new AssertionError(t); - } - } - - - /** - * @param loader {@link ClassLoader} to get module from. - * @return {@link Module} of the class. - */ - static Module getLoaderModule(ClassLoader loader) { - try { - return (Module) CLASS_LOADER_MDOULE.invokeExact(loader); - } catch (Throwable t) { - // That should never happen. - throw new AssertionError(t); - } - } - - static { - try { - Field field = Lookup.class.getDeclaredField("IMPL_LOOKUP"); - field.setAccessible(true); - MethodHandles.publicLookup(); - Lookup lookup = (Lookup) field.get(null); - MethodType type = MethodType.methodType(Module.class); - CLASS_MODULE = lookup.findVirtual(Class.class, "getModule", type); - CLASS_LOADER_MDOULE = lookup.findVirtual(ClassLoader.class, "getUnnamedModule", type); - } catch (NoSuchMethodException | IllegalAccessException | NoSuchFieldException ex) { - throw new ExceptionInInitializerError(ex); - } - } -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/VMUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/VMUtils.java deleted file mode 100644 index 55a3081af..000000000 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/VMUtils.java +++ /dev/null @@ -1,270 +0,0 @@ -package org.jackhuang.hmcl.util; - -import com.sun.javafx.application.PlatformImpl; -import javafx.application.Platform; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.HashMap; -import java.util.HashSet; -import java.util.logging.Level; - -/** - * Dependent and non-dependent platform utilities for VM. - * - * @author xxDark - */ -public final class VMUtils { - private static int vmVersion = -1; - - /** - * Deny all constructions. - */ - private VMUtils() { } - - /** - * Appends URL to the {@link URLClassLoader}. - * - * @param cl the classloader to add {@link URL} for. - * @param url the {@link URL} to add. - */ - public static void addURL(ClassLoader cl, URL url) { - if (cl instanceof URLClassLoader) { - addURL0(cl, url); - } else { - addURL1(cl, url); - } - } - - /** - * @return running VM version. - */ - public static int getVmVersion() { - if (vmVersion < 0) { - // Check for class version, ez - String property = System.getProperty("java.class.version", ""); - if (!property.isEmpty()) - return vmVersion = (int) (Float.parseFloat(property) - ClassUtils.VERSION_OFFSET); - // Odd, not found. Try the spec version - Logging.LOG.warning("Using fallback vm-version fetch, no value for 'java.class.version'"); - property = System.getProperty("java.vm.specification.version", ""); - if (property.contains(".")) - return vmVersion = (int) Float.parseFloat(property.substring(property.indexOf('.') + 1)); - else if (!property.isEmpty()) - return vmVersion = Integer.parseInt(property); - // Very odd - Logging.LOG.warning("Fallback vm-version fetch failed, defaulting to 8"); - return 8; - } - return vmVersion; - } - - private static void addURL0(ClassLoader loader, URL url) { - Method method; - try { - method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - } catch (NoSuchMethodException ex) { - throw new RuntimeException("No 'addURL' method in java.net.URLClassLoader", ex); - } - method.setAccessible(true); - try { - method.invoke(loader, url); - } catch (IllegalAccessException ex) { - throw new IllegalStateException("'addURL' became inaccessible", ex); - } catch (InvocationTargetException ex) { - throw new RuntimeException("Error adding URL", ex.getTargetException()); - } - } - - private static void addURL1(ClassLoader loader, URL url) { - Class currentClass = loader.getClass(); - do { - Field field; - try { - field = currentClass.getDeclaredField("ucp"); - } catch (NoSuchFieldException ignored) { - continue; - } - field.setAccessible(true); - Object ucp; - try { - ucp = field.get(loader); - } catch (IllegalAccessException ex) { - throw new IllegalStateException("'ucp' became inaccessible", ex); - } - String className; - if (getVmVersion() < 9) { - className = "sun.misc.URLClassPath"; - } else { - className = "jdk.internal.misc.URLClassPath"; - } - Method method; - try { - method = Class.forName(className, true, null).getDeclaredMethod("addURL", URL.class); - } catch (NoSuchMethodException ex) { - throw new RuntimeException("No 'addURL' method in " + className, ex); - } catch (ClassNotFoundException ex) { - throw new RuntimeException(className + " was not found", ex); - } - method.setAccessible(true); - try { - method.invoke(ucp, url); - break; - } catch (IllegalAccessException ex) { - throw new IllegalStateException("'addURL' became inaccessible", ex); - } catch (InvocationTargetException ex) { - throw new RuntimeException("Error adding URL", ex.getTargetException()); - } - } while ((currentClass=currentClass.getSuperclass()) != Object.class); - throw new IllegalArgumentException("No 'ucp' field in " + loader); - } - - /** - * Closes {@link URLClassLoader}. - * - * @param loader - * Loader to close. - * - * @throws IOException - * When I/O error occurs. - */ - public static void close(URLClassLoader loader) throws IOException { - loader.close(); - } - - /** - * Sets parent class loader. - * - * @param loader - * Loader to change parent for. - * @param parent - * New parent loader. - */ - public static void setParent(ClassLoader loader, ClassLoader parent) { - Field field; - try { - field = ClassLoader.class.getDeclaredField("parent"); - } catch (NoSuchFieldException ex) { - throw new RuntimeException("No 'parent' field in java.lang.ClassLoader", ex); - } - field.setAccessible(true); - try { - field.set(loader, parent); - } catch (IllegalAccessException ex) { - throw new IllegalStateException("'parent' became inaccessible", ex); - } - } - - /** - * Initializes toolkit. - */ - public static void tkIint() { - if (getVmVersion() < 9) { - PlatformImpl.startup(() -> {}); - } else { - Method m; - try { - m = Platform.class.getDeclaredMethod("startup", Runnable.class); - } catch (NoSuchMethodException ex) { - throw new RuntimeException("javafx.application.Platform.startup(Runnable) is missing", ex); - } - m.setAccessible(true); - try { - m.invoke(null, (Runnable) () -> {}); - } catch (IllegalAccessException ex) { - throw new IllegalStateException("'startup' became inaccessible", ex); - } catch (InvocationTargetException ex) { - throw new RuntimeException("Unable to initialize toolkit", ex.getTargetException()); - } - } - } - - /** - * Patches JDK stuff. - */ - public static void patch() { - if (getVmVersion() > 8) { - openPackages(); - patchReflectionFilters(); - } - } - - /** - * Opens all packages. - */ - private static void openPackages() { - try { - Method export = Module.class.getDeclaredMethod("implAddOpens", String.class); - export.setAccessible(true); - HashSet modules = new HashSet<>(); - Class classBase = VMUtils.class; - Module base = Java9Util.getClassModule(classBase); - if (base.getLayer() != null) - modules.addAll(base.getLayer().modules()); - modules.addAll(ModuleLayer.boot().modules()); - for (ClassLoader cl = classBase.getClassLoader(); cl != null; cl = cl.getParent()) { - modules.add(Java9Util.getLoaderModule(cl)); - } - for (Module module : modules) { - for (String name : module.getPackages()) { - try { - export.invoke(module, name); - } catch (Exception ex) { - Logging.LOG.log(Level.SEVERE, "Could not export package " + name + " in module " + module, ex); - } - } - } - } catch (Exception ex) { - Logging.LOG.log(Level.SEVERE, "Could not export packages", ex); - } - } - - /** - * Patches reflection filters. - */ - private static void patchReflectionFilters() { - Class klass; - try { - klass = Class.forName("jdk.internal.reflect.Reflection", - true, null); - } catch (ClassNotFoundException ex) { - throw new RuntimeException("Unable to locate 'jdk.internal.reflect.Reflection' class", ex); - } - try { - Field[] fields; - try { - Method m = Class.class.getDeclaredMethod("getDeclaredFieldsImpl"); - m.setAccessible(true); - fields = (Field[]) m.invoke(klass); - } catch (NoSuchMethodException | InvocationTargetException ex) { - try { - Method m = Class.class.getDeclaredMethod("getDeclaredFields0", Boolean.TYPE); - m.setAccessible(true); - fields = (Field[]) m.invoke(klass, false); - } catch (InvocationTargetException | NoSuchMethodException ex1) { - ex.addSuppressed(ex1); - throw new RuntimeException("Unable to get all class fields", ex); - } - } - int c = 0; - for (Field field : fields) { - String name = field.getName(); - if ("fieldFilterMap".equals(name) || "methodFilterMap".equals(name)) { - field.setAccessible(true); - field.set(null, new HashMap<>(0)); - if (++c == 2) { - return; - } - } - } - throw new RuntimeException("One of field patches did not apply properly. " + - "Expected to patch two fields, but patched: " + c); - } catch (IllegalAccessException ex) { - throw new RuntimeException("Unable to patch reflection filters", ex); - } - } -}