11/*
2- * Copyright 2016-2025 DiffPlug
2+ * Copyright 2016-2026 DiffPlug
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1515 */
1616package com .diffplug .spotless .java ;
1717
18- import java .lang .invoke .MethodHandle ;
18+ import static java .lang .Class .forName ;
19+ import static java .lang .invoke .MethodHandles .privateLookupIn ;
20+
1921import java .lang .invoke .MethodHandles ;
20- import java .lang .reflect .Field ;
2122import java .lang .reflect .Method ;
2223import java .lang .reflect .Modifier ;
2324import java .util .ArrayList ;
2627import java .util .List ;
2728import java .util .Map ;
2829
29- import javax .annotation .Nullable ;
30-
3130import org .slf4j .Logger ;
3231import org .slf4j .LoggerFactory ;
3332
3433import com .diffplug .spotless .Jvm ;
3534
3635import edu .umd .cs .findbugs .annotations .SuppressFBWarnings ;
37- import sun .misc .Unsafe ;
3836
3937final class ModuleHelper {
4038 private static final Logger LOGGER = LoggerFactory .getLogger (ModuleHelper .class );
@@ -86,7 +84,7 @@ private static List<String> unavailableRequiredPackages() {
8684 final String key = e .getKey ();
8785 final String value = e .getValue ();
8886 try {
89- final Class <?> clazz = Class . forName (key + "." + value );
87+ final Class <?> clazz = forName (key + "." + value );
9088 if (clazz .isEnum ()) {
9189 clazz .getMethod ("values" ).invoke (null );
9290 } else {
@@ -103,42 +101,34 @@ private static List<String> unavailableRequiredPackages() {
103101
104102 @ SuppressWarnings ("unchecked" )
105103 private static void openPackages (Collection <String > packagesToOpen ) throws Throwable {
106- final Collection <?> modules = allModules ();
107- if (modules == null ) {
108- return ;
109- }
110- final Field unsafeField = Unsafe .class .getDeclaredField ("theUnsafe" );
111- unsafeField .setAccessible (true );
112- final Unsafe unsafe = (Unsafe ) unsafeField .get (null );
113- final Field implLookupField = MethodHandles .Lookup .class .getDeclaredField ("IMPL_LOOKUP" );
114- final MethodHandles .Lookup lookup = (MethodHandles .Lookup ) unsafe .getObject (
115- unsafe .staticFieldBase (implLookupField ),
116- unsafe .staticFieldOffset (implLookupField ));
117- final MethodHandle modifiers = lookup .findSetter (Method .class , "modifiers" , Integer .TYPE );
118- final Method exportMethod = Class .forName ("java.lang.Module" ).getDeclaredMethod ("implAddOpens" , String .class );
119- modifiers .invokeExact (exportMethod , Modifier .PUBLIC );
120- for (Object module : modules ) {
121- final Collection <String > packages = (Collection <String >) module .getClass ().getMethod ("getPackages" ).invoke (module );
122- for (String name : packages ) {
104+ // Use MethodHandles.privateLookupIn for accessing private fields in JDK 9+
105+ // Get the IMPL_LOOKUP field using MethodHandles
106+ MethodHandles .Lookup .class .getDeclaredField ("IMPL_LOOKUP" ).setAccessible (true );
107+ // Use MethodHandles to modify method accessibility
108+ var exportMethod = forName ("java.lang.Module" ).getDeclaredMethod ("implAddOpens" , String .class );
109+ // Set method to public using MethodHandle
110+ privateLookupIn (MethodHandles .Lookup .class , MethodHandles .lookup ())
111+ .findSetter (Method .class , "modifiers" , int .class )
112+ .invokeExact (exportMethod , Modifier .PUBLIC );
113+ for (var module : allModules ()) {
114+ for (var name : (Collection <String >) module .getClass ().getMethod ("getPackages" ).invoke (module )) {
123115 if (packagesToOpen .contains (name )) {
124116 exportMethod .invoke (module , name );
125117 }
126118 }
127119 }
128120 }
129121
130- @ Nullable @ SuppressFBWarnings ("REC_CATCH_EXCEPTION" ) // workaround JDK11
122+ @ SuppressFBWarnings ("REC_CATCH_EXCEPTION" ) // workaround JDK11
131123 private static Collection <?> allModules () {
132124 // calling ModuleLayer.boot().modules() by reflection
133125 try {
134- final Object boot = Class .forName ("java.lang.ModuleLayer" ).getMethod ("boot" ).invoke (null );
135- if (boot == null ) {
136- return null ;
137- }
138- final Object modules = boot .getClass ().getMethod ("modules" ).invoke (boot );
139- return (Collection <?>) modules ;
126+ var boot = forName ("java.lang.ModuleLayer" ).getMethod ("boot" ).invoke (null );
127+ return boot != null
128+ ? (Collection <?>) boot .getClass ().getMethod ("modules" ).invoke (boot )
129+ : List .of ();
140130 } catch (Exception ignore ) {
141- return null ;
131+ return List . of () ;
142132 }
143133 }
144134}
0 commit comments