1
1
/*
2
- * Copyright (c) 2015, 2024 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2015, 2025 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
34
34
import java .lang .module .ModuleReference ;
35
35
import java .lang .reflect .Constructor ;
36
36
import java .net .URI ;
37
- import java .net .URLConnection ;
38
37
import java .nio .ByteBuffer ;
39
38
import java .nio .file .Files ;
40
39
import java .nio .file .Path ;
54
53
import java .util .stream .Stream ;
55
54
import java .util .stream .StreamSupport ;
56
55
57
- import jdk .internal .jimage .ImageLocation ;
58
56
import jdk .internal .jimage .ImageReader ;
59
57
import jdk .internal .jimage .ImageReaderFactory ;
60
58
import jdk .internal .access .JavaNetUriAccess ;
@@ -210,7 +208,7 @@ public static ModuleFinder ofSystem() {
210
208
}
211
209
212
210
/**
213
- * Parses the module-info.class of all module in the runtime image and
211
+ * Parses the {@code module-info.class} of all modules in the runtime image and
214
212
* returns a ModuleFinder to find the modules.
215
213
*
216
214
* @apiNote The returned ModuleFinder is thread safe.
@@ -219,20 +217,16 @@ private static ModuleFinder ofModuleInfos() {
219
217
// parse the module-info.class in every module
220
218
Map <String , ModuleInfo .Attributes > nameToAttributes = new HashMap <>();
221
219
Map <String , byte []> nameToHash = new HashMap <>();
222
- ImageReader reader = SystemImage .reader ();
223
- for (String mn : reader .getModuleNames ()) {
224
- ImageLocation loc = reader .findLocation (mn , "module-info.class" );
225
- ModuleInfo .Attributes attrs
226
- = ModuleInfo .read (reader .getResourceBuffer (loc ), null );
227
220
228
- nameToAttributes .put (mn , attrs );
221
+ allModuleAttributes ().forEach (attrs -> {
222
+ nameToAttributes .put (attrs .descriptor ().name (), attrs );
229
223
ModuleHashes hashes = attrs .recordedHashes ();
230
224
if (hashes != null ) {
231
225
for (String name : hashes .names ()) {
232
226
nameToHash .computeIfAbsent (name , k -> hashes .hashFor (name ));
233
227
}
234
228
}
235
- }
229
+ });
236
230
237
231
// create a ModuleReference for each module
238
232
Set <ModuleReference > mrefs = new HashSet <>();
@@ -253,6 +247,40 @@ private static ModuleFinder ofModuleInfos() {
253
247
return new SystemModuleFinder (mrefs , nameToModule );
254
248
}
255
249
250
+ /**
251
+ * Parses the {@code module-info.class} of all modules in the runtime image and
252
+ * returns a stream of {@link ModuleInfo.Attributes Attributes} for them. The
253
+ * returned attributes are in no specific order.
254
+ */
255
+ private static Stream <ModuleInfo .Attributes > allModuleAttributes () {
256
+ // System-wide image reader.
257
+ ImageReader reader = SystemImage .reader ();
258
+ try {
259
+ return reader .findNode ("/modules" )
260
+ .getChildNames ()
261
+ .map (mn -> readModuleAttributes (reader , mn ));
262
+ } catch (IOException e ) {
263
+ throw new Error ("Error reading root /modules entry" , e );
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Returns the module's "module-info", returning a holder for its class file
269
+ * attributes. Every module is required to have a valid {@code module-info.class}.
270
+ */
271
+ private static ModuleInfo .Attributes readModuleAttributes (ImageReader reader , String moduleName ) {
272
+ Exception err = null ;
273
+ try {
274
+ ImageReader .Node node = reader .findNode (moduleName + "/module-info.class" );
275
+ if (node != null && node .isResource ()) {
276
+ return ModuleInfo .read (reader .getResourceBuffer (node ), null );
277
+ }
278
+ } catch (IOException | UncheckedIOException e ) {
279
+ err = e ;
280
+ }
281
+ throw new Error ("Missing or invalid module-info.class for module: " + moduleName , err );
282
+ }
283
+
256
284
/**
257
285
* A ModuleFinder that finds module in an array or set of modules.
258
286
*/
@@ -382,34 +410,18 @@ private static class SystemModuleReader implements ModuleReader {
382
410
this .module = module ;
383
411
}
384
412
385
- /**
386
- * Returns the ImageLocation for the given resource, {@code null}
387
- * if not found.
388
- */
389
- private ImageLocation findImageLocation (String name ) throws IOException {
390
- Objects .requireNonNull (name );
391
- if (closed )
392
- throw new IOException ("ModuleReader is closed" );
393
- ImageReader imageReader = SystemImage .reader ();
394
- if (imageReader != null ) {
395
- return imageReader .findLocation (module , name );
396
- } else {
397
- // not an images build
398
- return null ;
399
- }
400
- }
401
-
402
413
/**
403
414
* Returns {@code true} if the given resource exists, {@code false}
404
415
* if not found.
405
416
*/
406
- private boolean containsImageLocation (String name ) throws IOException {
407
- Objects .requireNonNull (name );
417
+ private boolean containsResource (String resourcePath ) throws IOException {
418
+ Objects .requireNonNull (resourcePath );
408
419
if (closed )
409
420
throw new IOException ("ModuleReader is closed" );
410
421
ImageReader imageReader = SystemImage .reader ();
411
422
if (imageReader != null ) {
412
- return imageReader .verifyLocation (module , name );
423
+ ImageReader .Node node = imageReader .findNode ("/modules" + resourcePath );
424
+ return node != null && node .isResource ();
413
425
} else {
414
426
// not an images build
415
427
return false ;
@@ -418,8 +430,9 @@ private boolean containsImageLocation(String name) throws IOException {
418
430
419
431
@ Override
420
432
public Optional <URI > find (String name ) throws IOException {
421
- if (containsImageLocation (name )) {
422
- URI u = JNUA .create ("jrt" , "/" + module + "/" + name );
433
+ String resourcePath = "/" + module + "/" + name ;
434
+ if (containsResource (resourcePath )) {
435
+ URI u = JNUA .create ("jrt" , resourcePath );
423
436
return Optional .of (u );
424
437
} else {
425
438
return Optional .empty ();
@@ -442,14 +455,25 @@ private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
442
455
}
443
456
}
444
457
458
+ /**
459
+ * Returns the node for the given resource if found. If the name references
460
+ * a non-resource node, then {@code null} is returned.
461
+ */
462
+ private ImageReader .Node findResource (ImageReader reader , String name ) throws IOException {
463
+ Objects .requireNonNull (name );
464
+ if (closed ) {
465
+ throw new IOException ("ModuleReader is closed" );
466
+ }
467
+ String nodeName = "/modules/" + module + "/" + name ;
468
+ ImageReader .Node node = reader .findNode (nodeName );
469
+ return (node != null && node .isResource ()) ? node : null ;
470
+ }
471
+
445
472
@ Override
446
473
public Optional <ByteBuffer > read (String name ) throws IOException {
447
- ImageLocation location = findImageLocation (name );
448
- if (location != null ) {
449
- return Optional .of (SystemImage .reader ().getResourceBuffer (location ));
450
- } else {
451
- return Optional .empty ();
452
- }
474
+ ImageReader reader = SystemImage .reader ();
475
+ return Optional .ofNullable (findResource (reader , name ))
476
+ .map (reader ::getResourceBuffer );
453
477
}
454
478
455
479
@ Override
@@ -481,7 +505,7 @@ public void close() {
481
505
private static class ModuleContentSpliterator implements Spliterator <String > {
482
506
final String moduleRoot ;
483
507
final Deque <ImageReader .Node > stack ;
484
- Iterator <ImageReader . Node > iterator ;
508
+ Iterator <String > iterator ;
485
509
486
510
ModuleContentSpliterator (String module ) throws IOException {
487
511
moduleRoot = "/modules/" + module ;
@@ -502,13 +526,10 @@ private static class ModuleContentSpliterator implements Spliterator<String> {
502
526
private String next () throws IOException {
503
527
for (;;) {
504
528
while (iterator .hasNext ()) {
505
- ImageReader . Node node = iterator .next ();
506
- String name = node . getName ( );
529
+ String name = iterator .next ();
530
+ ImageReader . Node node = SystemImage . reader (). findNode ( name );
507
531
if (node .isDirectory ()) {
508
- // build node
509
- ImageReader .Node dir = SystemImage .reader ().findNode (name );
510
- assert dir .isDirectory ();
511
- stack .push (dir );
532
+ stack .push (node );
512
533
} else {
513
534
// strip /modules/$MODULE/ prefix
514
535
return name .substring (moduleRoot .length () + 1 );
@@ -520,7 +541,7 @@ private String next() throws IOException {
520
541
} else {
521
542
ImageReader .Node dir = stack .poll ();
522
543
assert dir .isDirectory ();
523
- iterator = dir .getChildren ().iterator ();
544
+ iterator = dir .getChildNames ().iterator ();
524
545
}
525
546
}
526
547
}
0 commit comments