@@ -45,27 +45,41 @@ private ModuleSupport() {
45
45
throw new AssertionError ("Utility class, should not be instantiated" );
46
46
}
47
47
48
- static ModuleFinder ofSyntheticPluginModule (String name , Path [] jarPaths , Set <String > requires , Set <String > uses ) {
48
+ static ModuleFinder ofSyntheticPluginModule (
49
+ String name ,
50
+ Path [] jarPaths ,
51
+ Set <String > requires ,
52
+ Set <String > uses ,
53
+ Predicate <String > isPackageInParentLayers
54
+ ) {
49
55
try {
50
56
return new InMemoryModuleFinder (
51
- new InMemoryModuleReference (createModuleDescriptor (name , jarPaths , requires , uses ), URI .create ("module:/" + name ))
57
+ new InMemoryModuleReference (
58
+ createModuleDescriptor (name , jarPaths , requires , uses , isPackageInParentLayers ),
59
+ URI .create ("module:/" + name )
60
+ )
52
61
);
53
62
} catch (IOException e ) {
54
63
throw new UncheckedIOException (e );
55
64
}
56
65
}
57
66
58
67
@ SuppressForbidden (reason = "need access to the jar file" )
59
- static ModuleDescriptor createModuleDescriptor (String name , Path [] jarPaths , Set <String > requires , Set <String > uses )
60
- throws IOException {
68
+ static ModuleDescriptor createModuleDescriptor (
69
+ String name ,
70
+ Path [] jarPaths ,
71
+ Set <String > requires ,
72
+ Set <String > uses ,
73
+ Predicate <String > isPackageInParentLayers
74
+ ) throws IOException {
61
75
var builder = ModuleDescriptor .newOpenModule (name ); // open module, for now
62
76
requires .stream ().forEach (builder ::requires );
63
77
uses .stream ().forEach (builder ::uses );
64
78
65
79
// scan the names of the entries in the JARs
66
80
Set <String > pkgs = new HashSet <>();
67
81
Map <String , List <String >> allBundledProviders = new HashMap <>();
68
- Set <String > allBundledServices = new HashSet <>();
82
+ Set <String > servicesUsedInBundle = new HashSet <>();
69
83
for (Path path : jarPaths ) {
70
84
assert path .getFileName ().toString ().endsWith (".jar" ) : "expected jars suffix, in path: " + path ;
71
85
try (JarFile jf = new JarFile (path .toFile (), true , ZipFile .OPEN_READ , Runtime .version ())) {
@@ -74,13 +88,13 @@ static ModuleDescriptor createModuleDescriptor(String name, Path[] jarPaths, Set
74
88
if (moduleInfo != null ) {
75
89
var descriptor = getDescriptorForModularJar (path );
76
90
pkgs .addAll (descriptor .packages ());
77
- allBundledServices .addAll (descriptor .uses ());
91
+ servicesUsedInBundle .addAll (descriptor .uses ());
78
92
for (ModuleDescriptor .Provides p : descriptor .provides ()) {
79
93
String serviceName = p .service ();
80
94
List <String > providersInModule = p .providers ();
81
95
82
96
allBundledProviders .compute (serviceName , (k , v ) -> createListOrAppend (v , providersInModule ));
83
- allBundledServices .add (serviceName );
97
+ servicesUsedInBundle .add (serviceName );
84
98
}
85
99
} else {
86
100
var scan = scan (jf );
@@ -92,21 +106,29 @@ static ModuleDescriptor createModuleDescriptor(String name, Path[] jarPaths, Set
92
106
List <String > providersInJar = getProvidersFromServiceFile (jf , serviceFileName );
93
107
94
108
allBundledProviders .compute (serviceName , (k , v ) -> createListOrAppend (v , providersInJar ));
95
- allBundledServices .add (serviceName );
109
+ servicesUsedInBundle .add (serviceName );
96
110
}
97
111
}
98
112
}
99
113
}
100
114
101
115
builder .packages (pkgs );
102
116
103
- // the module needs to use all services it provides, for the case of internal use
104
- allBundledServices .addAll (allBundledProviders .keySet ());
105
- // but we don't want to add any services we already got from the parent layer
106
- allBundledServices .removeAll (uses );
117
+ // we don't want to add any services we already got from the parent layer
118
+ servicesUsedInBundle .removeAll (uses );
107
119
108
- allBundledServices .forEach (builder ::uses );
109
- allBundledProviders .forEach (builder ::provides );
120
+ // Services that aren't exported in the parent layer or defined in our
121
+ // bundle. This can happen for optional (compile-time) dependencies
122
+ Set <String > missingServices = servicesUsedInBundle .stream ()
123
+ .filter (s -> isPackageInParentLayers .test (toPackageName (s , "." ).orElseThrow ()) == false )
124
+ .filter (s -> pkgs .contains (toPackageName (s , "." ).orElseThrow ()) == false )
125
+ .collect (Collectors .toSet ());
126
+
127
+ servicesUsedInBundle .stream ().filter (s -> missingServices .contains (s ) == false ).forEach (builder ::uses );
128
+ allBundledProviders .entrySet ()
129
+ .stream ()
130
+ .filter (e -> missingServices .contains (e .getKey ()) == false )
131
+ .forEach (e -> builder .provides (e .getKey (), e .getValue ()));
110
132
return builder .build ();
111
133
}
112
134
@@ -246,7 +268,7 @@ static boolean isJavaPlatformModule(ModuleDescriptor md) {
246
268
@ SuppressForbidden (reason = "need access to the jar file" )
247
269
private static List <String > getProvidersFromServiceFile (JarFile jf , String sf ) throws IOException {
248
270
try (BufferedReader bf = new BufferedReader (new InputStreamReader (jf .getInputStream (jf .getEntry (sf )), StandardCharsets .UTF_8 ))) {
249
- return bf .lines ().toList ();
271
+ return bf .lines ().filter ( Predicate . not ( l -> l . startsWith ( "#" ))). filter ( Predicate . not ( String :: isEmpty )). toList ();
250
272
}
251
273
}
252
274
0 commit comments