diff --git a/lib/src/main/java/com/diffplug/spotless/java/ModuleHelper.java b/lib/src/main/java/com/diffplug/spotless/java/ModuleHelper.java index 3023e2c20c..07e717cfde 100644 --- a/lib/src/main/java/com/diffplug/spotless/java/ModuleHelper.java +++ b/lib/src/main/java/com/diffplug/spotless/java/ModuleHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2025 DiffPlug + * Copyright 2016-2026 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,10 @@ */ package com.diffplug.spotless.java; -import java.lang.invoke.MethodHandle; +import static java.lang.Class.forName; +import static java.lang.invoke.MethodHandles.privateLookupIn; + import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -26,15 +27,12 @@ import java.util.List; import java.util.Map; -import javax.annotation.Nullable; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.diffplug.spotless.Jvm; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import sun.misc.Unsafe; final class ModuleHelper { private static final Logger LOGGER = LoggerFactory.getLogger(ModuleHelper.class); @@ -86,7 +84,7 @@ private static List unavailableRequiredPackages() { final String key = e.getKey(); final String value = e.getValue(); try { - final Class clazz = Class.forName(key + "." + value); + final Class clazz = forName(key + "." + value); if (clazz.isEnum()) { clazz.getMethod("values").invoke(null); } else { @@ -103,23 +101,17 @@ private static List unavailableRequiredPackages() { @SuppressWarnings("unchecked") private static void openPackages(Collection packagesToOpen) throws Throwable { - final Collection modules = allModules(); - if (modules == null) { - return; - } - final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); - unsafeField.setAccessible(true); - final Unsafe unsafe = (Unsafe) unsafeField.get(null); - final Field implLookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP"); - final MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject( - unsafe.staticFieldBase(implLookupField), - unsafe.staticFieldOffset(implLookupField)); - final MethodHandle modifiers = lookup.findSetter(Method.class, "modifiers", Integer.TYPE); - final Method exportMethod = Class.forName("java.lang.Module").getDeclaredMethod("implAddOpens", String.class); - modifiers.invokeExact(exportMethod, Modifier.PUBLIC); - for (Object module : modules) { - final Collection packages = (Collection) module.getClass().getMethod("getPackages").invoke(module); - for (String name : packages) { + // Use MethodHandles.privateLookupIn for accessing private fields in JDK 9+ + // Get the IMPL_LOOKUP field using MethodHandles + MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP").setAccessible(true); + // Use MethodHandles to modify method accessibility + var exportMethod = forName("java.lang.Module").getDeclaredMethod("implAddOpens", String.class); + // Set method to public using MethodHandle + privateLookupIn(MethodHandles.Lookup.class, MethodHandles.lookup()) + .findSetter(Method.class, "modifiers", int.class) + .invokeExact(exportMethod, Modifier.PUBLIC); + for (var module : allModules()) { + for (var name : (Collection) module.getClass().getMethod("getPackages").invoke(module)) { if (packagesToOpen.contains(name)) { exportMethod.invoke(module, name); } @@ -127,18 +119,16 @@ private static void openPackages(Collection packagesToOpen) throws Throw } } - @Nullable @SuppressFBWarnings("REC_CATCH_EXCEPTION") // workaround JDK11 + @SuppressFBWarnings("REC_CATCH_EXCEPTION") // workaround JDK11 private static Collection allModules() { // calling ModuleLayer.boot().modules() by reflection try { - final Object boot = Class.forName("java.lang.ModuleLayer").getMethod("boot").invoke(null); - if (boot == null) { - return null; - } - final Object modules = boot.getClass().getMethod("modules").invoke(boot); - return (Collection) modules; + var boot = forName("java.lang.ModuleLayer").getMethod("boot").invoke(null); + return boot != null + ? (Collection) boot.getClass().getMethod("modules").invoke(boot) + : List.of(); } catch (Exception ignore) { - return null; + return List.of(); } } }