Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/module/AutomaticModulesTest.java
41149 views
1
/*
2
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/**
25
* @test
26
* @bug 8142968 8253751
27
* @library /test/lib
28
* @build AutomaticModulesTest
29
* jdk.test.lib.util.JarUtils
30
* jdk.test.lib.util.ModuleUtils
31
* @run testng AutomaticModulesTest
32
* @summary Basic tests for automatic modules
33
*/
34
35
import java.io.IOException;
36
import java.lang.module.Configuration;
37
import java.lang.module.FindException;
38
import java.lang.module.ModuleDescriptor;
39
import java.lang.module.ModuleDescriptor.Requires.Modifier;
40
import java.lang.module.ModuleFinder;
41
import java.lang.module.ModuleReference;
42
import java.lang.module.ResolutionException;
43
import java.lang.module.ResolvedModule;
44
import java.nio.file.Files;
45
import java.nio.file.Path;
46
import java.util.Optional;
47
import java.util.Set;
48
import java.util.jar.Attributes;
49
import java.util.jar.Manifest;
50
import java.util.stream.Collectors;
51
import java.util.stream.Stream;
52
53
import jdk.test.lib.util.JarUtils;
54
import jdk.test.lib.util.ModuleUtils;
55
56
import org.testng.annotations.DataProvider;
57
import org.testng.annotations.Test;
58
import static org.testng.Assert.*;
59
60
@Test
61
public class AutomaticModulesTest {
62
63
private static final Path USER_DIR = Path.of(System.getProperty("user.dir"));
64
65
@DataProvider(name = "jarnames")
66
public Object[][] createJarNames() {
67
return new Object[][] {
68
69
// JAR file name module-name[/version]
70
71
{ "foo.jar", "foo" },
72
{ "foo4j.jar", "foo4j", },
73
74
{ "foo1.jar", "foo1" },
75
{ "foo10.jar", "foo10" },
76
77
{ "foo-1.jar", "foo/1" },
78
{ "foo-1.2.jar", "foo/1.2" },
79
{ "foo-1.2.3.jar", "foo/1.2.3" },
80
{ "foo-1.2.3.4.jar", "foo/1.2.3.4" },
81
82
{ "foo-10.jar", "foo/10" },
83
{ "foo-10.20.jar", "foo/10.20" },
84
{ "foo-10.20.30.jar", "foo/10.20.30" },
85
{ "foo-10.20.30.40.jar", "foo/10.20.30.40" },
86
87
{ "foo-bar.jar", "foo.bar" },
88
{ "foo-bar-1.jar", "foo.bar/1" },
89
{ "foo-bar-1.2.jar", "foo.bar/1.2"},
90
{ "foo-bar-10.jar", "foo.bar/10" },
91
{ "foo-bar-10.20.jar", "foo.bar/10.20" },
92
93
{ "foo.bar1.jar", "foo.bar1" },
94
{ "foo.bar10.jar", "foo.bar10" },
95
96
{ "foo-1.2-SNAPSHOT.jar", "foo/1.2-SNAPSHOT" },
97
{ "foo-bar-1.2-SNAPSHOT.jar", "foo.bar/1.2-SNAPSHOT" },
98
99
{ "foo--bar-1.0.jar", "foo.bar/1.0" },
100
{ "-foo-bar-1.0.jar", "foo.bar/1.0" },
101
{ "foo-bar--1.0.jar", "foo.bar/1.0" },
102
103
};
104
}
105
106
// JAR file names that do not map to a legal module name
107
@DataProvider(name = "badjarnames")
108
public Object[][] createBadNames() {
109
return new Object[][]{
110
111
{ ".jar", null },
112
{ "_.jar", null },
113
114
{ "foo.1.jar", null },
115
{ "1foo.jar", null },
116
{ "foo.1bar.jar", null },
117
118
};
119
}
120
121
/**
122
* Test mapping of JAR file names to module names
123
*/
124
@Test(dataProvider = "jarnames")
125
public void testNames(String fn, String mid) throws IOException {
126
String[] s = mid.split("/");
127
String mn = s[0];
128
String vs = (s.length == 2) ? s[1] : null;
129
130
Path dir = Files.createTempDirectory(USER_DIR, "mods");
131
Path jf = dir.resolve(fn);
132
133
// create empty JAR file
134
createDummyJarFile(jf);
135
136
// create a ModuleFinder to find modules in the directory
137
ModuleFinder finder = ModuleFinder.of(dir);
138
139
// a module with the expected name should be found
140
Optional<ModuleReference> mref = finder.find(mn);
141
assertTrue(mref.isPresent(), mn + " not found");
142
143
ModuleDescriptor descriptor = mref.get().descriptor();
144
assertTrue(descriptor.isAutomatic());
145
assertEquals(descriptor.name(), mn);
146
if (vs == null) {
147
assertFalse(descriptor.version().isPresent());
148
} else {
149
assertEquals(descriptor.version().get().toString(), vs);
150
}
151
}
152
153
/**
154
* Test impossible mapping of JAR files to modules names
155
*/
156
@Test(dataProvider = "badjarnames", expectedExceptions = FindException.class)
157
public void testBadNames(String fn, String ignore) throws IOException {
158
Path dir = Files.createTempDirectory(USER_DIR, "mods");
159
Path jf = dir.resolve(fn);
160
161
// create empty JAR file
162
createDummyJarFile(jf);
163
164
// should throw FindException
165
ModuleFinder.of(dir).findAll();
166
}
167
168
@DataProvider(name = "modulenames")
169
public Object[][] createModuleNames() {
170
return new Object[][] {
171
{ "foo", null },
172
{ "foo", "1.0" },
173
{ "foo.bar", null },
174
{ "foo.bar", "1.0" },
175
{ "class_", null },
176
{ "class_", "1.0" },
177
};
178
}
179
180
@DataProvider(name = "badmodulenames")
181
public Object[][] createBadModuleNames() {
182
return new Object[][] {
183
{ "", null },
184
{ "", "1.0" },
185
{ "666", null },
186
{ "666", "1.0" },
187
{ "foo.class", null },
188
{ "foo.class", "1.0" },
189
};
190
}
191
192
/**
193
* Test JAR files with the Automatic-Module-Name attribute
194
*/
195
@Test(dataProvider = "modulenames")
196
public void testAutomaticModuleNameAttribute(String name, String vs)
197
throws IOException
198
{
199
Manifest man = new Manifest();
200
Attributes attrs = man.getMainAttributes();
201
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
202
attrs.put(new Attributes.Name("Automatic-Module-Name"), name);
203
204
Path dir = Files.createTempDirectory(USER_DIR, "mods");
205
String jar;
206
if (vs == null) {
207
jar = "m.jar";
208
} else {
209
jar = "m-" + vs + ".jar";
210
}
211
createDummyJarFile(dir.resolve(jar), man);
212
213
ModuleFinder finder = ModuleFinder.of(dir);
214
215
assertTrue(finder.findAll().size() == 1);
216
assertTrue(finder.find(name).isPresent());
217
218
ModuleReference mref = finder.find(name).get();
219
ModuleDescriptor descriptor = mref.descriptor();
220
assertEquals(descriptor.name(), name);
221
assertEquals(descriptor.version()
222
.map(ModuleDescriptor.Version::toString)
223
.orElse(null), vs);
224
}
225
226
/**
227
* Test JAR files with the Automatic-Module-Name attribute with a value
228
* that is not a legal module name.
229
*/
230
@Test(dataProvider = "badmodulenames", expectedExceptions = FindException.class)
231
public void testBadAutomaticModuleNameAttribute(String name, String ignore)
232
throws IOException
233
{
234
// should throw FindException
235
testAutomaticModuleNameAttribute(name, null);
236
}
237
238
/**
239
* Test all packages are exported
240
*/
241
public void testPackages() throws IOException {
242
Path dir = Files.createTempDirectory(USER_DIR, "mods");
243
createDummyJarFile(dir.resolve("m.jar"),
244
"p/C1.class", "p/C2.class", "q/C1.class");
245
246
ModuleFinder finder = ModuleFinder.of(dir);
247
Optional<ModuleReference> mref = finder.find("m");
248
assertTrue(mref.isPresent(), "m not found");
249
250
ModuleDescriptor descriptor = mref.get().descriptor();
251
assertTrue(descriptor.isAutomatic());
252
253
assertTrue(descriptor.packages().size() == 2);
254
assertTrue(descriptor.packages().contains("p"));
255
assertTrue(descriptor.packages().contains("q"));
256
257
assertTrue(descriptor.exports().isEmpty());
258
assertTrue(descriptor.opens().isEmpty());
259
}
260
261
/**
262
* Test class files in JAR file where the entry does not correspond to a
263
* legal package name.
264
*/
265
public void testBadPackage() throws IOException {
266
Path dir = Files.createTempDirectory(USER_DIR, "mods");
267
createDummyJarFile(dir.resolve("m.jar"), "p/C1.class", "p-/C2.class");
268
269
ModuleFinder finder = ModuleFinder.of(dir);
270
Optional<ModuleReference> mref = finder.find("m");
271
assertTrue(mref.isPresent(), "m not found");
272
273
ModuleDescriptor descriptor = mref.get().descriptor();
274
assertTrue(descriptor.isAutomatic());
275
276
assertTrue(descriptor.packages().size() == 1);
277
assertTrue(descriptor.packages().contains("p"));
278
279
assertTrue(descriptor.exports().isEmpty());
280
assertTrue(descriptor.opens().isEmpty());
281
}
282
283
/**
284
* Test non-class resources in a JAR file.
285
*/
286
public void testNonClassResources() throws IOException {
287
Path dir = Files.createTempDirectory(USER_DIR, "mods");
288
createDummyJarFile(dir.resolve("m.jar"),
289
"LICENSE",
290
"README",
291
"WEB-INF/tags",
292
"p/Type.class",
293
"p/resources/m.properties");
294
295
ModuleFinder finder = ModuleFinder.of(dir);
296
Optional<ModuleReference> mref = finder.find("m");
297
assertTrue(mref.isPresent(), "m not found");
298
299
ModuleDescriptor descriptor = mref.get().descriptor();
300
assertTrue(descriptor.isAutomatic());
301
302
assertTrue(descriptor.packages().size() == 1);
303
assertTrue(descriptor.packages().contains("p"));
304
}
305
306
/**
307
* Test .class file in unnamed package (top-level directory)
308
*/
309
@Test(expectedExceptions = FindException.class)
310
public void testClassInUnnamedPackage() throws IOException {
311
Path dir = Files.createTempDirectory(USER_DIR, "mods");
312
createDummyJarFile(dir.resolve("m.jar"), "Mojo.class");
313
ModuleFinder finder = ModuleFinder.of(dir);
314
finder.findAll();
315
}
316
317
/**
318
* Test JAR file with META-INF/services configuration file
319
*/
320
public void testServicesConfiguration() throws IOException {
321
String service = "p.S";
322
String provider = "p.S1";
323
324
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
325
326
// provider class
327
Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class");
328
Files.createDirectories(providerClass.getParent());
329
Files.createFile(providerClass);
330
331
// services configuration file
332
Path services = tmpdir.resolve("META-INF").resolve("services");
333
Files.createDirectories(services);
334
Files.write(services.resolve(service), Set.of(provider));
335
336
Path dir = Files.createTempDirectory(USER_DIR, "mods");
337
JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);
338
339
ModuleFinder finder = ModuleFinder.of(dir);
340
341
Optional<ModuleReference> mref = finder.find("m");
342
assertTrue(mref.isPresent(), "m not found");
343
344
ModuleDescriptor descriptor = mref.get().descriptor();
345
assertTrue(descriptor.provides().size() == 1);
346
ModuleDescriptor.Provides provides = descriptor.provides().iterator().next();
347
assertEquals(provides.service(), service);
348
assertTrue(provides.providers().size() == 1);
349
assertTrue(provides.providers().contains((provider)));
350
}
351
352
// META-INF/services files that don't map to legal service names
353
@DataProvider(name = "badservices")
354
public Object[][] createBadServices() {
355
return new Object[][] {
356
357
// service type provider type
358
{ "-", "p.S1" },
359
{ ".S", "p.S1" },
360
};
361
}
362
363
/**
364
* Test JAR file with META-INF/services configuration file with bad
365
* values or names.
366
*/
367
@Test(dataProvider = "badservices")
368
public void testBadServicesNames(String service, String provider)
369
throws IOException
370
{
371
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
372
Path services = tmpdir.resolve("META-INF").resolve("services");
373
Files.createDirectories(services);
374
Files.write(services.resolve(service), Set.of(provider));
375
Path dir = Files.createTempDirectory(USER_DIR, "mods");
376
JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);
377
378
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
379
assertTrue(omref.isPresent());
380
ModuleDescriptor descriptor = omref.get().descriptor();
381
assertTrue(descriptor.provides().isEmpty());
382
}
383
384
// META-INF/services configuration file entries that are not legal
385
@DataProvider(name = "badproviders")
386
public Object[][] createBadProviders() {
387
return new Object[][] {
388
389
// service type provider type
390
{ "p.S", "-" },
391
{ "p.S", "p..S1" },
392
{ "p.S", "S1." },
393
};
394
}
395
396
/**
397
* Test JAR file with META-INF/services configuration file with bad
398
* values or names.
399
*/
400
@Test(dataProvider = "badproviders", expectedExceptions = FindException.class)
401
public void testBadProviderNames(String service, String provider)
402
throws IOException
403
{
404
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
405
406
// provider class
407
Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class");
408
Files.createDirectories(providerClass.getParent());
409
Files.createFile(providerClass);
410
411
// services configuration file
412
Path services = tmpdir.resolve("META-INF").resolve("services");
413
Files.createDirectories(services);
414
Files.write(services.resolve(service), Set.of(provider));
415
416
Path dir = Files.createTempDirectory(USER_DIR, "mods");
417
JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);
418
419
// should throw FindException
420
ModuleFinder.of(dir).findAll();
421
}
422
423
/**
424
* Test JAR file with META-INF/services configuration file listing a
425
* provider that is not in the module.
426
*/
427
@Test(expectedExceptions = FindException.class)
428
public void testMissingProviderPackage() throws IOException {
429
Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");
430
431
// services configuration file
432
Path services = tmpdir.resolve("META-INF").resolve("services");
433
Files.createDirectories(services);
434
Files.write(services.resolve("p.S"), Set.of("q.P"));
435
436
Path dir = Files.createTempDirectory(USER_DIR, "mods");
437
JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);
438
439
// should throw FindException
440
ModuleFinder.of(dir).findAll();
441
}
442
443
/**
444
* Test that a JAR file with a Main-Class attribute results
445
* in a module with a main class.
446
*/
447
public void testMainClass() throws IOException {
448
String mainClass = "p.Main";
449
450
Manifest man = new Manifest();
451
Attributes attrs = man.getMainAttributes();
452
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
453
attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
454
455
Path dir = Files.createTempDirectory(USER_DIR, "mods");
456
String entry = mainClass.replace('.', '/') + ".class";
457
createDummyJarFile(dir.resolve("m.jar"), man, entry);
458
459
ModuleFinder finder = ModuleFinder.of(dir);
460
461
Configuration parent = ModuleLayer.boot().configuration();
462
Configuration cf = resolve(parent, finder, "m");
463
464
ModuleDescriptor descriptor = findDescriptor(cf, "m");
465
466
assertTrue(descriptor.mainClass().isPresent());
467
assertEquals(descriptor.mainClass().get(), mainClass);
468
}
469
470
// Main-Class files that do not map to a legal qualified type name
471
@DataProvider(name = "badmainclass")
472
public Object[][] createBadMainClass() {
473
return new Object[][] {
474
{ "p..Main", null },
475
{ "p-.Main", null },
476
477
};
478
}
479
480
/**
481
* Test that a JAR file with a Main-Class attribute that is not a qualified
482
* type name.
483
*/
484
@Test(dataProvider = "badmainclass")
485
public void testBadMainClass(String mainClass, String ignore) throws IOException {
486
Manifest man = new Manifest();
487
Attributes attrs = man.getMainAttributes();
488
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
489
attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
490
491
Path dir = Files.createTempDirectory(USER_DIR, "mods");
492
String entry = mainClass.replace('.', '/') + ".class";
493
createDummyJarFile(dir.resolve("m.jar"), man, entry);
494
495
// bad Main-Class value should be ignored
496
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
497
assertTrue(omref.isPresent());
498
ModuleDescriptor descriptor = omref.get().descriptor();
499
assertFalse(descriptor.mainClass().isPresent());
500
}
501
502
/**
503
* Test that a JAR file with a Main-Class attribute that is not in the module
504
*/
505
public void testMissingMainClassPackage() throws IOException {
506
Manifest man = new Manifest();
507
Attributes attrs = man.getMainAttributes();
508
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
509
attrs.put(Attributes.Name.MAIN_CLASS, "p.Main");
510
511
Path dir = Files.createTempDirectory(USER_DIR, "mods");
512
createDummyJarFile(dir.resolve("m.jar"), man);
513
514
// Main-Class should be ignored because package p is not in module
515
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
516
assertTrue(omref.isPresent());
517
ModuleDescriptor descriptor = omref.get().descriptor();
518
assertFalse(descriptor.mainClass().isPresent());
519
}
520
521
/**
522
* Basic test of a configuration created with automatic modules.
523
* a requires b*
524
* a requires c*
525
* b*
526
* c*
527
*/
528
public void testConfiguration1() throws Exception {
529
ModuleDescriptor descriptor1
530
= ModuleDescriptor.newModule("a")
531
.requires("b")
532
.requires("c")
533
.requires("java.base")
534
.build();
535
536
// b and c are automatic modules
537
Path dir = Files.createTempDirectory(USER_DIR, "mods");
538
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
539
createDummyJarFile(dir.resolve("c.jar"), "q/T.class");
540
541
// module finder locates a and the modules in the directory
542
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
543
ModuleFinder finder2 = ModuleFinder.of(dir);
544
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
545
546
Configuration parent = ModuleLayer.boot().configuration();
547
Configuration cf = resolve(parent, finder, "a");
548
549
assertTrue(cf.modules().size() == 3);
550
assertTrue(cf.findModule("a").isPresent());
551
assertTrue(cf.findModule("b").isPresent());
552
assertTrue(cf.findModule("c").isPresent());
553
554
ResolvedModule base = cf.findModule("java.base").get();
555
assertTrue(base.configuration() == ModuleLayer.boot().configuration());
556
ResolvedModule a = cf.findModule("a").get();
557
ResolvedModule b = cf.findModule("b").get();
558
ResolvedModule c = cf.findModule("c").get();
559
560
// b && c only require java.base
561
assertTrue(b.reference().descriptor().requires().size() == 1);
562
assertTrue(c.reference().descriptor().requires().size() == 1);
563
564
// readability
565
566
assertTrue(a.reads().size() == 3);
567
assertTrue(a.reads().contains(base));
568
assertTrue(a.reads().contains(b));
569
assertTrue(a.reads().contains(c));
570
571
assertTrue(b.reads().contains(a));
572
assertTrue(b.reads().contains(c));
573
testReadAllBootModules(cf, "b"); // b reads all modules in boot layer
574
575
assertTrue(c.reads().contains(a));
576
assertTrue(c.reads().contains(b));
577
testReadAllBootModules(cf, "c"); // c reads all modules in boot layer
578
579
}
580
581
/**
582
* Basic test of a configuration created with automatic modules
583
* a requires b
584
* b requires c*
585
* c*
586
* d*
587
*/
588
public void testInConfiguration2() throws IOException {
589
ModuleDescriptor descriptor1
590
= ModuleDescriptor.newModule("a")
591
.requires("b")
592
.requires("java.base")
593
.build();
594
595
ModuleDescriptor descriptor2
596
= ModuleDescriptor.newModule("b")
597
.requires("c")
598
.requires("java.base")
599
.build();
600
601
// c and d are automatic modules
602
Path dir = Files.createTempDirectory(USER_DIR, "mods");
603
createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
604
createDummyJarFile(dir.resolve("d.jar"), "q/T.class");
605
606
// module finder locates a and the modules in the directory
607
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
608
ModuleFinder finder2 = ModuleFinder.of(dir);
609
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
610
611
Configuration parent = ModuleLayer.boot().configuration();
612
Configuration cf = resolve(parent, finder, "a", "d");
613
614
assertTrue(cf.modules().size() == 4);
615
assertTrue(cf.findModule("a").isPresent());
616
assertTrue(cf.findModule("b").isPresent());
617
assertTrue(cf.findModule("c").isPresent());
618
assertTrue(cf.findModule("d").isPresent());
619
620
// c && d should only require java.base
621
assertTrue(findDescriptor(cf, "c").requires().size() == 1);
622
assertTrue(findDescriptor(cf, "d").requires().size() == 1);
623
624
// readability
625
626
ResolvedModule base = cf.findModule("java.base").get();
627
assertTrue(base.configuration() == ModuleLayer.boot().configuration());
628
ResolvedModule a = cf.findModule("a").get();
629
ResolvedModule b = cf.findModule("b").get();
630
ResolvedModule c = cf.findModule("c").get();
631
ResolvedModule d = cf.findModule("d").get();
632
633
assertTrue(a.reads().size() == 2);
634
assertTrue(a.reads().contains(b));
635
assertTrue(a.reads().contains(base));
636
637
assertTrue(b.reads().size() == 3);
638
assertTrue(b.reads().contains(c));
639
assertTrue(b.reads().contains(d));
640
assertTrue(b.reads().contains(base));
641
642
assertTrue(c.reads().contains(a));
643
assertTrue(c.reads().contains(b));
644
assertTrue(c.reads().contains(d));
645
testReadAllBootModules(cf, "c"); // c reads all modules in boot layer
646
647
assertTrue(d.reads().contains(a));
648
assertTrue(d.reads().contains(b));
649
assertTrue(d.reads().contains(c));
650
testReadAllBootModules(cf, "d"); // d reads all modules in boot layer
651
}
652
653
/**
654
* Basic test of a configuration created with automatic modules
655
* a requires b
656
* b requires transitive c*
657
* c*
658
* d*
659
*/
660
public void testInConfiguration3() throws IOException {
661
ModuleDescriptor descriptor1
662
= ModuleDescriptor.newModule("a")
663
.requires("b")
664
.requires("java.base")
665
.build();
666
667
ModuleDescriptor descriptor2
668
= ModuleDescriptor.newModule("b")
669
.requires(Set.of(Modifier.TRANSITIVE), "c")
670
.requires("java.base")
671
.build();
672
673
// c and d are automatic modules
674
Path dir = Files.createTempDirectory(USER_DIR, "mods");
675
createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
676
createDummyJarFile(dir.resolve("d.jar"), "q/T.class");
677
678
// module finder locates a and the modules in the directory
679
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
680
ModuleFinder finder2 = ModuleFinder.of(dir);
681
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
682
683
Configuration parent = ModuleLayer.boot().configuration();
684
Configuration cf = resolve(parent, finder, "a", "d");
685
686
assertTrue(cf.modules().size() == 4);
687
assertTrue(cf.findModule("a").isPresent());
688
assertTrue(cf.findModule("b").isPresent());
689
assertTrue(cf.findModule("c").isPresent());
690
assertTrue(cf.findModule("d").isPresent());
691
692
ResolvedModule base = cf.findModule("java.base").get();
693
assertTrue(base.configuration() == ModuleLayer.boot().configuration());
694
ResolvedModule a = cf.findModule("a").get();
695
ResolvedModule b = cf.findModule("b").get();
696
ResolvedModule c = cf.findModule("c").get();
697
ResolvedModule d = cf.findModule("d").get();
698
699
// c && d should only require java.base
700
assertTrue(findDescriptor(cf, "c").requires().size() == 1);
701
assertTrue(findDescriptor(cf, "d").requires().size() == 1);
702
703
// readability
704
705
assertTrue(a.reads().size() == 4);
706
assertTrue(a.reads().contains(b));
707
assertTrue(a.reads().contains(c));
708
assertTrue(a.reads().contains(d));
709
assertTrue(a.reads().contains(base));
710
711
assertTrue(b.reads().size() == 3);
712
assertTrue(b.reads().contains(c));
713
assertTrue(b.reads().contains(d));
714
assertTrue(b.reads().contains(base));
715
716
assertTrue(reads(cf, "b", "c"));
717
assertTrue(reads(cf, "b", "d"));
718
assertTrue(reads(cf, "b", "java.base"));
719
720
assertTrue(c.reads().contains(a));
721
assertTrue(c.reads().contains(b));
722
assertTrue(c.reads().contains(d));
723
testReadAllBootModules(cf, "c"); // c reads all modules in boot layer
724
725
assertTrue(d.reads().contains(a));
726
assertTrue(d.reads().contains(b));
727
assertTrue(d.reads().contains(c));
728
testReadAllBootModules(cf, "d"); // d reads all modules in boot layer
729
}
730
731
/**
732
* Basic test to ensure that no automatic modules are resolved when
733
* an automatic module is not a root or required by other modules.
734
*/
735
public void testInConfiguration4() throws IOException {
736
ModuleDescriptor descriptor1
737
= ModuleDescriptor.newModule("m1")
738
.requires("java.base")
739
.build();
740
741
// automatic modules
742
Path dir = Files.createTempDirectory(USER_DIR, "mods");
743
createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");
744
createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");
745
createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class");
746
747
// module finder locates m1 and the modules in the directory
748
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
749
ModuleFinder finder2 = ModuleFinder.of(dir);
750
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
751
752
Configuration parent = ModuleLayer.boot().configuration();
753
Configuration cf = resolve(parent, finder, "m1");
754
755
// ensure that no automatic module is resolved
756
assertTrue(cf.modules().size() == 1);
757
assertTrue(cf.findModule("m1").isPresent());
758
}
759
760
/**
761
* Basic test to ensure that if an automatic module is resolved then
762
* all observable automatic modules are resolved.
763
*/
764
public void testInConfiguration5() throws IOException {
765
// m1 requires m2
766
ModuleDescriptor descriptor1
767
= ModuleDescriptor.newModule("m1")
768
.requires("m2").build();
769
770
// m2 requires automatic module
771
ModuleDescriptor descriptor2
772
= ModuleDescriptor.newModule("m2")
773
.requires("auto1")
774
.build();
775
776
// automatic modules
777
Path dir = Files.createTempDirectory(USER_DIR, "mods");
778
createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");
779
createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");
780
createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class");
781
782
// module finder locates m1, m2, and the modules in the directory
783
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
784
ModuleFinder finder2 = ModuleFinder.of(dir);
785
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
786
787
Configuration parent = ModuleLayer.boot().configuration();
788
Configuration cf = resolve(parent, finder, "m1");
789
790
// all automatic modules should be resolved
791
assertTrue(cf.modules().size() == 5);
792
assertTrue(cf.findModule("m1").isPresent());
793
assertTrue(cf.findModule("m2").isPresent());
794
assertTrue(cf.findModule("auto1").isPresent());
795
assertTrue(cf.findModule("auto2").isPresent());
796
assertTrue(cf.findModule("auto3").isPresent());
797
798
ResolvedModule base = parent.findModule("java.base")
799
.orElseThrow(() -> new RuntimeException());
800
ResolvedModule m1 = cf.findModule("m1").get();
801
ResolvedModule m2 = cf.findModule("m2").get();
802
ResolvedModule auto1 = cf.findModule("auto1").get();
803
ResolvedModule auto2 = cf.findModule("auto2").get();
804
ResolvedModule auto3 = cf.findModule("auto3").get();
805
806
// m1 does not read the automatic modules
807
assertTrue(m1.reads().size() == 2);
808
assertTrue(m1.reads().contains(m2));
809
assertTrue(m1.reads().contains(base));
810
811
// m2 should read all the automatic modules
812
assertTrue(m2.reads().size() == 4);
813
assertTrue(m2.reads().contains(auto1));
814
assertTrue(m2.reads().contains(auto2));
815
assertTrue(m2.reads().contains(auto3));
816
assertTrue(m2.reads().contains(base));
817
818
assertTrue(auto1.reads().contains(m1));
819
assertTrue(auto1.reads().contains(m2));
820
assertTrue(auto1.reads().contains(auto2));
821
assertTrue(auto1.reads().contains(auto3));
822
assertTrue(auto1.reads().contains(base));
823
824
assertTrue(auto2.reads().contains(m1));
825
assertTrue(auto2.reads().contains(m2));
826
assertTrue(auto2.reads().contains(auto1));
827
assertTrue(auto2.reads().contains(auto3));
828
assertTrue(auto2.reads().contains(base));
829
830
assertTrue(auto3.reads().contains(m1));
831
assertTrue(auto3.reads().contains(m2));
832
assertTrue(auto3.reads().contains(auto1));
833
assertTrue(auto3.reads().contains(auto2));
834
assertTrue(auto3.reads().contains(base));
835
}
836
837
/**
838
* Basic test of automatic modules in a child configuration. All automatic
839
* modules that are found with the before finder should be resolved. The
840
* automatic modules that are found by the after finder and not shadowed
841
* by the before finder, or parent configurations, should also be resolved.
842
*/
843
public void testInConfiguration6() throws IOException {
844
// m1 requires auto1
845
ModuleDescriptor descriptor1
846
= ModuleDescriptor.newModule("m1")
847
.requires("auto1")
848
.build();
849
850
Path dir = Files.createTempDirectory(USER_DIR, "mods");
851
createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");
852
853
// module finder locates m1 and auto1
854
ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
855
ModuleFinder finder2 = ModuleFinder.of(dir);
856
ModuleFinder finder = ModuleFinder.compose(finder1, finder2);
857
858
Configuration parent = ModuleLayer.boot().configuration();
859
Configuration cf1 = resolve(parent, finder, "m1");
860
861
assertTrue(cf1.modules().size() == 2);
862
assertTrue(cf1.findModule("m1").isPresent());
863
assertTrue(cf1.findModule("auto1").isPresent());
864
865
ResolvedModule base = parent.findModule("java.base")
866
.orElseThrow(() -> new RuntimeException());
867
ResolvedModule m1 = cf1.findModule("m1").get();
868
ResolvedModule auto1 = cf1.findModule("auto1").get();
869
870
assertTrue(m1.reads().size() == 2);
871
assertTrue(m1.reads().contains(auto1));
872
assertTrue(m1.reads().contains(base));
873
874
assertTrue(auto1.reads().contains(m1));
875
assertTrue(auto1.reads().contains(base));
876
877
878
// create child configuration - the after finder locates auto1
879
880
dir = Files.createTempDirectory(USER_DIR, "mods");
881
createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");
882
ModuleFinder beforeFinder = ModuleFinder.of(dir);
883
884
dir = Files.createTempDirectory(USER_DIR, "mods");
885
createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");
886
createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");
887
createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class");
888
ModuleFinder afterFinder = ModuleFinder.of(dir);
889
890
Configuration cf2 = cf1.resolve(beforeFinder, afterFinder, Set.of("auto2"));
891
892
// auto1 should be found in parent and should not be in cf2
893
assertTrue(cf2.modules().size() == 2);
894
assertTrue(cf2.findModule("auto2").isPresent());
895
assertTrue(cf2.findModule("auto3").isPresent());
896
897
ResolvedModule auto2 = cf2.findModule("auto2").get();
898
ResolvedModule auto3 = cf2.findModule("auto3").get();
899
900
assertTrue(auto2.reads().contains(m1));
901
assertTrue(auto2.reads().contains(auto1));
902
assertTrue(auto2.reads().contains(auto3));
903
assertTrue(auto2.reads().contains(base));
904
905
assertTrue(auto3.reads().contains(m1));
906
assertTrue(auto3.reads().contains(auto1));
907
assertTrue(auto3.reads().contains(auto2));
908
assertTrue(auto3.reads().contains(base));
909
}
910
911
/**
912
* Basic test for a module requiring an automatic module in a parent
913
* configuration. If an explicit module in a child configuration reads an
914
* automatic module in a parent configuration then it should read all
915
* automatic modules in the parent configuration.
916
*/
917
public void testInConfiguration7() throws Exception {
918
// m1 requires auto1
919
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")
920
.requires("auto1")
921
.build();
922
923
Path dir1 = Files.createTempDirectory(USER_DIR, "mods");
924
createDummyJarFile(dir1.resolve("auto1.jar"), "p1/C.class");
925
createDummyJarFile(dir1.resolve("auto2.jar"), "p2/C.class");
926
927
// module finder locates m1, auto1, and auto2
928
ModuleFinder finder1 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1),
929
ModuleFinder.of(dir1));
930
931
Configuration parent = ModuleLayer.boot().configuration();
932
ResolvedModule base = parent.findModule("java.base").orElseThrow();
933
934
Configuration cf1 = resolve(parent, finder1, "m1");
935
assertTrue(cf1.modules().size() == 3);
936
937
ResolvedModule m1 = cf1.findModule("m1").orElseThrow();
938
ResolvedModule auto1 = cf1.findModule("auto1").orElseThrow();
939
ResolvedModule auto2 = cf1.findModule("auto2").orElseThrow();
940
941
assertTrue(m1.reads().size() == 3);
942
assertTrue(m1.reads().contains(base));
943
assertTrue(m1.reads().contains(auto1));
944
assertTrue(m1.reads().contains(auto2));
945
946
assertTrue(auto1.reads().contains(base));
947
assertTrue(auto1.reads().contains(m1));
948
assertTrue(auto1.reads().contains(auto2));
949
950
assertTrue(auto2.reads().contains(base));
951
assertTrue(auto2.reads().contains(m1));
952
assertTrue(auto2.reads().contains(auto1));
953
954
// m2 requires auto1
955
ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2")
956
.requires("auto1")
957
.build();
958
959
Path dir2 = Files.createTempDirectory(USER_DIR, "mods");
960
createDummyJarFile(dir1.resolve("auto3.jar"), "p3/C.class");
961
962
// module finder locates m2 and auto3
963
ModuleFinder finder2 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor2),
964
ModuleFinder.of(dir2));
965
966
Configuration cf2 = resolve(cf1, finder2, "m2");
967
assertTrue(cf2.modules().size() == 1); // auto3 should not be resolved
968
969
ResolvedModule m2 = cf2.findModule("m2").orElseThrow();
970
971
assertTrue(m2.reads().size() == 3);
972
assertTrue(m2.reads().contains(base));
973
assertTrue(m2.reads().contains(auto1));
974
assertTrue(m2.reads().contains(auto2));
975
}
976
977
/**
978
* Basic test of a configuration created with automatic modules
979
* a requires b* and c*
980
* b* contains p
981
* c* contains p
982
*/
983
@Test(expectedExceptions = { ResolutionException.class })
984
public void testDuplicateSuppliers1() throws IOException {
985
ModuleDescriptor descriptor
986
= ModuleDescriptor.newModule("a")
987
.requires("b")
988
.requires("c")
989
.build();
990
991
// c and d are automatic modules with the same package
992
Path dir = Files.createTempDirectory(USER_DIR, "mods");
993
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
994
createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
995
996
// module finder locates 'a' and the modules in the directory
997
ModuleFinder finder
998
= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
999
ModuleFinder.of(dir));
1000
1001
Configuration parent = ModuleLayer.boot().configuration();
1002
resolve(parent, finder, "a");
1003
}
1004
1005
/**
1006
* Basic test of a configuration created with automatic modules
1007
* a contains p, requires b*
1008
* b* contains p
1009
*/
1010
@Test(expectedExceptions = { ResolutionException.class })
1011
public void testDuplicateSuppliers2() throws IOException {
1012
ModuleDescriptor descriptor
1013
= ModuleDescriptor.newModule("a")
1014
.packages(Set.of("p"))
1015
.requires("b")
1016
.build();
1017
1018
// c and d are automatic modules with the same package
1019
Path dir = Files.createTempDirectory(USER_DIR, "mods");
1020
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
1021
1022
// module finder locates 'a' and the modules in the directory
1023
ModuleFinder finder
1024
= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
1025
ModuleFinder.of(dir));
1026
1027
Configuration parent = ModuleLayer.boot().configuration();
1028
resolve(parent, finder, "a");
1029
}
1030
1031
/**
1032
* Basic test of layer containing automatic modules
1033
*/
1034
public void testInLayer() throws IOException {
1035
ModuleDescriptor descriptor
1036
= ModuleDescriptor.newModule("a")
1037
.requires("b")
1038
.requires("c")
1039
.build();
1040
1041
// b and c are simple JAR files
1042
Path dir = Files.createTempDirectory(USER_DIR, "mods");
1043
createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
1044
createDummyJarFile(dir.resolve("c.jar"), "q/T2.class");
1045
1046
// module finder locates a and the modules in the directory
1047
ModuleFinder finder
1048
= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
1049
ModuleFinder.of(dir));
1050
1051
Configuration parent = ModuleLayer.boot().configuration();
1052
Configuration cf = resolve(parent, finder, "a");
1053
assertTrue(cf.modules().size() == 3);
1054
1055
// each module gets its own loader
1056
ModuleLayer layer = ModuleLayer.boot().defineModules(cf, mn -> new ClassLoader() { });
1057
1058
// an unnamed module
1059
Module unnamed = (new ClassLoader() { }).getUnnamedModule();
1060
1061
Module b = layer.findModule("b").get();
1062
assertTrue(b.isNamed());
1063
assertTrue(b.canRead(unnamed));
1064
testsReadsAll(b, layer);
1065
1066
Module c = layer.findModule("c").get();
1067
assertTrue(c.isNamed());
1068
assertTrue(b.canRead(unnamed));
1069
testsReadsAll(c, layer);
1070
}
1071
1072
/**
1073
* Test miscellaneous methods.
1074
*/
1075
public void testMisc() throws IOException {
1076
Path dir = Files.createTempDirectory(USER_DIR, "mods");
1077
Path m_jar = createDummyJarFile(dir.resolve("m.jar"), "p/T.class");
1078
1079
ModuleFinder finder = ModuleFinder.of(m_jar);
1080
1081
assertTrue(finder.find("m").isPresent());
1082
ModuleDescriptor m = finder.find("m").get().descriptor();
1083
1084
// test miscellaneous methods
1085
assertTrue(m.isAutomatic());
1086
assertFalse(m.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC));
1087
}
1088
1089
/**
1090
* Invokes parent.resolve to resolve the given root modules.
1091
*/
1092
static Configuration resolve(Configuration parent,
1093
ModuleFinder finder,
1094
String... roots) {
1095
return parent.resolve(finder, ModuleFinder.of(), Set.of(roots));
1096
}
1097
1098
/**
1099
* Finds a module in the given configuration or its parents, returning
1100
* the module descriptor (or null if not found)
1101
*/
1102
static ModuleDescriptor findDescriptor(Configuration cf, String name) {
1103
Optional<ResolvedModule> om = cf.findModule(name);
1104
if (om.isPresent()) {
1105
return om.get().reference().descriptor();
1106
} else {
1107
return null;
1108
}
1109
}
1110
1111
/**
1112
* Test that a module in a configuration reads all modules in the boot
1113
* configuration.
1114
*/
1115
static void testReadAllBootModules(Configuration cf, String mn) {
1116
1117
Set<String> bootModules = ModuleLayer.boot().modules().stream()
1118
.map(Module::getName)
1119
.collect(Collectors.toSet());
1120
1121
bootModules.forEach(other -> assertTrue(reads(cf, mn, other)));
1122
1123
}
1124
1125
/**
1126
* Test that the given Module reads all module in the given layer
1127
* and its parent layers.
1128
*/
1129
static void testsReadsAll(Module m, ModuleLayer layer) {
1130
// check that m reads all modules in the layer
1131
layer.configuration().modules().stream()
1132
.map(ResolvedModule::name)
1133
.map(layer::findModule)
1134
.map(Optional::get)
1135
.forEach(other -> assertTrue(m.canRead(other)));
1136
1137
// also check parent layers
1138
layer.parents().forEach(l -> testsReadsAll(m, l));
1139
}
1140
1141
/**
1142
* Returns {@code true} if the configuration contains module mn1
1143
* that reads module mn2.
1144
*/
1145
static boolean reads(Configuration cf, String mn1, String mn2) {
1146
Optional<ResolvedModule> om = cf.findModule(mn1);
1147
if (!om.isPresent())
1148
return false;
1149
1150
return om.get().reads().stream()
1151
.map(ResolvedModule::name)
1152
.anyMatch(mn2::equals);
1153
}
1154
1155
/**
1156
* Creates a JAR file, optionally with a manifest, and with the given
1157
* entries. The entries will be empty in the resulting JAR file.
1158
*/
1159
static Path createDummyJarFile(Path jarfile, Manifest man, String... entries)
1160
throws IOException
1161
{
1162
Path dir = Files.createTempDirectory(USER_DIR, "tmp");
1163
1164
for (String entry : entries) {
1165
Path file = dir.resolve(entry);
1166
Path parent = file.getParent();
1167
if (parent != null)
1168
Files.createDirectories(parent);
1169
Files.createFile(file);
1170
}
1171
1172
Path[] paths = Stream.of(entries).map(Path::of).toArray(Path[]::new);
1173
JarUtils.createJarFile(jarfile, man, dir, paths);
1174
return jarfile;
1175
}
1176
1177
/**
1178
* Creates a JAR file and with the given entries. The entries will be empty
1179
* in the resulting JAR file.
1180
*/
1181
static Path createDummyJarFile(Path jarfile, String... entries)
1182
throws IOException
1183
{
1184
return createDummyJarFile(jarfile, null, entries);
1185
}
1186
1187
}
1188
1189