55import java .lang .invoke .MethodHandles ;
66import java .lang .invoke .MethodType ;
77import java .lang .module .Configuration ;
8- import java .lang .module .ModuleDescriptor ;
98import java .lang .module .ModuleFinder ;
109import java .lang .module .ModuleReference ;
1110import java .lang .module .ResolvedModule ;
1211import java .lang .reflect .Field ;
1312import java .nio .file .Path ;
1413import java .nio .file .Paths ;
15- import java .util .Arrays ;
1614import java .util .HashMap ;
1715import java .util .HashSet ;
1816import java .util .List ;
1917import java .util .Map ;
18+ import java .util .Optional ;
2019import java .util .Set ;
2120import java .util .function .Function ;
2221import java .util .stream .Collectors ;
22+ import java .util .stream .Stream ;
2323
24+ import io .github .zekerzhayard .forgewrapper .util .CheckedLambdaUtil ;
2425import sun .misc .Unsafe ;
2526
2627public class ModuleUtil {
@@ -46,39 +47,22 @@ private static MethodHandles.Lookup getImplLookup() {
4647 */
4748 @ SuppressWarnings ("unchecked" )
4849 public static void addModules (String modulePath ) throws Throwable {
49- // Find all extra modules
50- ModuleFinder finder = ModuleFinder .of (Arrays . stream (modulePath .split (File .pathSeparator )).map (Paths ::get ).toArray (Path []::new ));
50+ // Find all extra modules, exclude all existing modules
51+ ModuleFinder finder = ModuleFinder .of (Stream . of (modulePath .split (File .pathSeparator )).map (Paths ::get ). filter ( p -> ModuleFinder . of ( p ). findAll (). stream (). noneMatch ( mref -> ModuleLayer . boot (). findModule ( mref . descriptor (). name ()). isPresent ()) ).toArray (Path []::new ));
5152 MethodHandle loadModuleMH = IMPL_LOOKUP .findVirtual (Class .forName ("jdk.internal.loader.BuiltinClassLoader" ), "loadModule" , MethodType .methodType (void .class , ModuleReference .class ));
5253
53- // Resolve modules to a new config
54- Configuration config = Configuration .resolveAndBind (finder , List .of (ModuleLayer .boot ().configuration ()), finder , finder .findAll ().stream ().peek (mref -> {
55- try {
56- // Load all extra modules in system class loader (unnamed modules for now)
57- loadModuleMH .invokeWithArguments (ClassLoader .getSystemClassLoader (), mref );
58- } catch (Throwable throwable ) {
59- throw new RuntimeException (throwable );
60- }
61- }).map (ModuleReference ::descriptor ).map (ModuleDescriptor ::name ).collect (Collectors .toList ()));
54+ // Resolve modules to a new config and load all extra modules in system class loader (unnamed modules for now)
55+ Configuration config = Configuration .resolveAndBind (finder , List .of (ModuleLayer .boot ().configuration ()), finder , finder .findAll ().stream ().filter (mref -> !ModuleLayer .boot ().findModule (mref .descriptor ().name ()).isPresent ()).peek (CheckedLambdaUtil .wrapConsumer (mref -> loadModuleMH .invokeWithArguments (ClassLoader .getSystemClassLoader (), mref ))).map (mref -> mref .descriptor ().name ()).collect (Collectors .toList ()));
6256
6357 // Copy the new config graph to boot module layer config
6458 MethodHandle graphGetter = IMPL_LOOKUP .findGetter (Configuration .class , "graph" , Map .class );
6559 HashMap <ResolvedModule , Set <ResolvedModule >> graphMap = new HashMap <>((Map <ResolvedModule , Set <ResolvedModule >>) graphGetter .invokeWithArguments (config ));
6660 MethodHandle cfSetter = IMPL_LOOKUP .findSetter (ResolvedModule .class , "cf" , Configuration .class );
6761 // Reset all extra resolved modules config to boot module layer config
68- graphMap .forEach ((k , v ) -> {
69- try {
70- cfSetter .invokeWithArguments (k , ModuleLayer .boot ().configuration ());
71- v .forEach (m -> {
72- try {
73- cfSetter .invokeWithArguments (m , ModuleLayer .boot ().configuration ());
74- } catch (Throwable throwable ) {
75- throw new RuntimeException (throwable );
76- }
77- });
78- } catch (Throwable throwable ) {
79- throw new RuntimeException (throwable );
80- }
81- });
62+ graphMap .forEach (CheckedLambdaUtil .wrapBiConsumer ((k , v ) -> {
63+ cfSetter .invokeWithArguments (k , ModuleLayer .boot ().configuration ());
64+ v .forEach (CheckedLambdaUtil .wrapConsumer (m -> cfSetter .invokeWithArguments (m , ModuleLayer .boot ().configuration ())));
65+ }));
8266 graphMap .putAll ((Map <ResolvedModule , Set <ResolvedModule >>) graphGetter .invokeWithArguments (ModuleLayer .boot ().configuration ()));
8367 IMPL_LOOKUP .findSetter (Configuration .class , "graph" , Map .class ).invokeWithArguments (ModuleLayer .boot ().configuration (), new HashMap <>(graphMap ));
8468
@@ -88,13 +72,13 @@ public static void addModules(String modulePath) throws Throwable {
8872 HashSet <ResolvedModule > modulesSet = new HashSet <>(config .modules ());
8973 modulesSetter .invokeWithArguments (ModuleLayer .boot ().configuration (), new HashSet <>(modulesSet ));
9074
91- // Prepare to add all of the new config "nameToModule" to boot module layer config
75+ // Prepare to add all the new config "nameToModule" to boot module layer config
9276 MethodHandle nameToModuleGetter = IMPL_LOOKUP .findGetter (Configuration .class , "nameToModule" , Map .class );
9377 HashMap <String , ResolvedModule > nameToModuleMap = new HashMap <>((Map <String , ResolvedModule >) nameToModuleGetter .invokeWithArguments (ModuleLayer .boot ().configuration ()));
9478 nameToModuleMap .putAll ((Map <String , ResolvedModule >) nameToModuleGetter .invokeWithArguments (config ));
9579 IMPL_LOOKUP .findSetter (Configuration .class , "nameToModule" , Map .class ).invokeWithArguments (ModuleLayer .boot ().configuration (), new HashMap <>(nameToModuleMap ));
9680
97- // Define all extra modules and add all of the new config "nameToModule" to boot module layer config
81+ // Define all extra modules and add all the new config "nameToModule" to boot module layer config
9882 ((Map <String , Module >) IMPL_LOOKUP .findGetter (ModuleLayer .class , "nameToModule" , Map .class ).invokeWithArguments (ModuleLayer .boot ())).putAll ((Map <String , Module >) IMPL_LOOKUP .findStatic (Module .class , "defineModules" , MethodType .methodType (Map .class , Configuration .class , Function .class , ModuleLayer .class )).invokeWithArguments (ModuleLayer .boot ().configuration (), (Function <String , ClassLoader >) name -> ClassLoader .getSystemClassLoader (), ModuleLayer .boot ()));
9983
10084 // Add all of resolved modules
@@ -107,66 +91,56 @@ public static void addModules(String modulePath) throws Throwable {
10791
10892 // Add reads from extra modules to jdk modules
10993 MethodHandle implAddReadsMH = IMPL_LOOKUP .findVirtual (Module .class , "implAddReads" , MethodType .methodType (void .class , Module .class ));
110- config .modules ().forEach (rm -> ModuleLayer .boot ().findModule (rm .name ()).ifPresent (m -> oldBootModules .forEach (brm -> ModuleLayer .boot ().findModule (brm .name ()).ifPresent (bm -> {
111- try {
112- implAddReadsMH .invokeWithArguments (m , bm );
113- } catch (Throwable throwable ) {
114- throw new RuntimeException (throwable );
115- }
116- }))));
94+ config .modules ().forEach (rm -> ModuleLayer .boot ().findModule (rm .name ()).ifPresent (m -> oldBootModules .forEach (brm -> ModuleLayer .boot ().findModule (brm .name ()).ifPresent (CheckedLambdaUtil .wrapConsumer (bm -> implAddReadsMH .invokeWithArguments (m , bm ))))));
11795 }
11896
119- public static void addExports (List <String > exports ) throws Throwable {
120- MethodHandle implAddExportsMH = IMPL_LOOKUP . findVirtual ( Module . class , "implAddExports" , MethodType . methodType ( void . class , String . class , Module . class ) );
121- MethodHandle implAddExportsToAllUnnamedMH = IMPL_LOOKUP . findVirtual ( Module . class , "implAddExportsToAllUnnamed" , MethodType . methodType ( void . class , String . class ));
97+ public static void addExports (List <String > exports ) {
98+ TypeToAdd . EXPORTS . implAdd ( exports );
99+ }
122100
123- addExtra (exports , implAddExportsMH , implAddExportsToAllUnnamedMH );
101+ public static void addOpens (List <String > opens ) {
102+ TypeToAdd .OPENS .implAdd (opens );
124103 }
125104
126- public static void addOpens ( List < String > opens ) throws Throwable {
127- MethodHandle implAddOpensMH = IMPL_LOOKUP . findVirtual ( Module . class , "implAddOpens" , MethodType . methodType ( void . class , String . class , Module . class ));
128- MethodHandle implAddOpensToAllUnnamedMH = IMPL_LOOKUP . findVirtual ( Module . class , "implAddOpensToAllUnnamed" , MethodType . methodType ( void . class , String . class ) );
105+ private enum TypeToAdd {
106+ EXPORTS ( "Exports" ),
107+ OPENS ( "Opens" );
129108
130- addExtra ( opens , implAddOpensMH , implAddOpensToAllUnnamedMH ) ;
131- }
109+ private final MethodHandle implAddMH ;
110+ private final MethodHandle implAddToAllUnnamedMH ;
132111
133- private static void addExtra (List <String > extras , MethodHandle implAddExtraMH , MethodHandle implAddExtraToAllUnnamedMH ) {
134- extras .forEach (extra -> {
135- ParserData data = parseModuleExtra (extra );
136- if (data != null ) {
137- ModuleLayer .boot ().findModule (data .module ).ifPresent (m -> {
138- try {
139- if ("ALL-UNNAMED" .equals (data .target )) {
140- implAddExtraToAllUnnamedMH .invokeWithArguments (m , data .packages );
141- } else {
142- ModuleLayer .boot ().findModule (data .target ).ifPresent (tm -> {
143- try {
144- implAddExtraMH .invokeWithArguments (m , data .packages , tm );
145- } catch (Throwable t ) {
146- throw new RuntimeException (t );
147- }
148- });
149- }
150- } catch (Throwable t ) {
151- throw new RuntimeException (t );
152- }
153- });
112+ TypeToAdd (String name ) {
113+ try {
114+ this .implAddMH = IMPL_LOOKUP .findVirtual (Module .class , "implAdd" + name , MethodType .methodType (void .class , String .class , Module .class ));
115+ this .implAddToAllUnnamedMH = IMPL_LOOKUP .findVirtual (Module .class , "implAdd" + name + "ToAllUnnamed" , MethodType .methodType (void .class , String .class ));
116+ } catch (Throwable t ) {
117+ throw new RuntimeException (t );
154118 }
155- });
119+ }
120+
121+ void implAdd (List <String > extras ) {
122+ extras .stream ().map (ModuleUtil ::parseModuleExtra ).filter (Optional ::isPresent ).map (Optional ::get ).forEach (CheckedLambdaUtil .wrapConsumer (data -> ModuleLayer .boot ().findModule (data .module ).ifPresent (CheckedLambdaUtil .wrapConsumer (m -> {
123+ if ("ALL-UNNAMED" .equals (data .target )) {
124+ this .implAddToAllUnnamedMH .invokeWithArguments (m , data .packages );
125+ } else {
126+ ModuleLayer .boot ().findModule (data .target ).ifPresent (CheckedLambdaUtil .wrapConsumer (tm -> this .implAddMH .invokeWithArguments (m , data .packages , tm )));
127+ }
128+ }))));
129+ }
156130 }
157131
158132 // <module>/<package>=<target>
159- private static ParserData parseModuleExtra (String extra ) {
133+ private static Optional < ParserData > parseModuleExtra (String extra ) {
160134 String [] all = extra .split ("=" , 2 );
161135 if (all .length < 2 ) {
162- return null ;
136+ return Optional . empty () ;
163137 }
164138
165139 String [] source = all [0 ].split ("/" , 2 );
166140 if (source .length < 2 ) {
167- return null ;
141+ return Optional . empty () ;
168142 }
169- return new ParserData (source [0 ], source [1 ], all [1 ]);
143+ return Optional . of ( new ParserData (source [0 ], source [1 ], all [1 ]) );
170144 }
171145
172146 private static class ParserData {
@@ -182,14 +156,10 @@ private static class ParserData {
182156 }
183157
184158 // ForgeWrapper need some extra settings to invoke BootstrapLauncher.
185- public static void setupBootstrapLauncher () throws Throwable {
186- MethodHandle implAddOpensMH = IMPL_LOOKUP .findVirtual (Module .class , "implAddOpens" , MethodType .methodType (void .class , String .class , Module .class ));
187- ModuleLayer .boot ().findModule ("cpw.mods.bootstraplauncher" ).ifPresent (m -> {
188- try {
189- implAddOpensMH .invokeWithArguments (m , "cpw.mods.bootstraplauncher" , ModuleUtil .class .getModule ());
190- } catch (Throwable t ) {
191- throw new RuntimeException (t );
192- }
193- });
159+ public static Class <?> setupBootstrapLauncher (Class <?> mainClass ) throws Throwable {
160+ if (!mainClass .getModule ().isOpen (mainClass .getPackageName (), ModuleUtil .class .getModule ())) {
161+ TypeToAdd .OPENS .implAddMH .invokeWithArguments (mainClass .getModule (), mainClass .getPackageName (), ModuleUtil .class .getModule ());
162+ }
163+ return mainClass ;
194164 }
195165}
0 commit comments