< prev index next >

src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java

Print this page
@@ -1,7 +1,7 @@
  /*
-  * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
+  * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this

@@ -32,11 +32,10 @@
  import java.lang.module.ModuleFinder;
  import java.lang.module.ModuleReader;
  import java.lang.module.ModuleReference;
  import java.lang.reflect.Constructor;
  import java.net.URI;
- import java.net.URLConnection;
  import java.nio.ByteBuffer;
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.util.ArrayDeque;
  import java.util.Collections;

@@ -52,11 +51,10 @@
  import java.util.function.Consumer;
  import java.util.function.Supplier;
  import java.util.stream.Stream;
  import java.util.stream.StreamSupport;
  
- import jdk.internal.jimage.ImageLocation;
  import jdk.internal.jimage.ImageReader;
  import jdk.internal.jimage.ImageReaderFactory;
  import jdk.internal.access.JavaNetUriAccess;
  import jdk.internal.access.SharedSecrets;
  import jdk.internal.util.StaticProperty;

@@ -208,33 +206,29 @@
              throw new InternalError("Unable to detect the run-time image");
          return ModulePath.of(ModuleBootstrap.patcher(), dir);
      }
  
      /**
-      * Parses the module-info.class of all module in the runtime image and
+      * Parses the {@code module-info.class} of all modules in the runtime image and
       * returns a ModuleFinder to find the modules.
       *
       * @apiNote The returned ModuleFinder is thread safe.
       */
      private static ModuleFinder ofModuleInfos() {
          // parse the module-info.class in every module
          Map<String, ModuleInfo.Attributes> nameToAttributes = new HashMap<>();
          Map<String, byte[]> nameToHash = new HashMap<>();
-         ImageReader reader = SystemImage.reader();
-         for (String mn : reader.getModuleNames()) {
-             ImageLocation loc = reader.findLocation(mn, "module-info.class");
-             ModuleInfo.Attributes attrs
-                 = ModuleInfo.read(reader.getResourceBuffer(loc), null);
  
-             nameToAttributes.put(mn, attrs);
+         allModuleAttributes().forEach(attrs -> {
+             nameToAttributes.put(attrs.descriptor().name(), attrs);
              ModuleHashes hashes = attrs.recordedHashes();
              if (hashes != null) {
                  for (String name : hashes.names()) {
                      nameToHash.computeIfAbsent(name, k -> hashes.hashFor(name));
                  }
              }
-         }
+         });
  
          // create a ModuleReference for each module
          Set<ModuleReference> mrefs = new HashSet<>();
          Map<String, ModuleReference> nameToModule = new HashMap<>();
          for (Map.Entry<String, ModuleInfo.Attributes> e : nameToAttributes.entrySet()) {

@@ -251,10 +245,44 @@
          }
  
          return new SystemModuleFinder(mrefs, nameToModule);
      }
  
+     /**
+      * Parses the {@code module-info.class} of all modules in the runtime image and
+      * returns a stream of {@link ModuleInfo.Attributes Attributes} for them. The
+      * returned attributes are in no specific order.
+      */
+     private static Stream<ModuleInfo.Attributes> allModuleAttributes() {
+         // System-wide image reader.
+         ImageReader reader = SystemImage.reader();
+         try {
+             return reader.findNode("/modules")
+                     .getChildNames()
+                     .map(mn -> readModuleAttributes(reader, mn));
+         } catch (IOException e) {
+             throw new Error("Error reading root /modules entry", e);
+         }
+     }
+ 
+     /**
+      * Returns the module's "module-info", returning a holder for its class file
+      * attributes. Every module is required to have a valid {@code module-info.class}.
+      */
+     private static ModuleInfo.Attributes readModuleAttributes(ImageReader reader, String moduleName) {
+         Exception err = null;
+         try {
+             ImageReader.Node node = reader.findNode(moduleName + "/module-info.class");
+             if (node != null && node.isResource()) {
+                 return ModuleInfo.read(reader.getResourceBuffer(node), null);
+             }
+         } catch (IOException | UncheckedIOException e) {
+             err = e;
+         }
+         throw new Error("Missing or invalid module-info.class for module: " + moduleName, err);
+     }
+ 
      /**
       * A ModuleFinder that finds module in an array or set of modules.
       */
      private static class SystemModuleFinder implements ModuleFinder {
          final Set<ModuleReference> mrefs;

@@ -380,48 +408,33 @@
  
          SystemModuleReader(String module) {
              this.module = module;
          }
  
-         /**
-          * Returns the ImageLocation for the given resource, {@code null}
-          * if not found.
-          */
-         private ImageLocation findImageLocation(String name) throws IOException {
-             Objects.requireNonNull(name);
-             if (closed)
-                 throw new IOException("ModuleReader is closed");
-             ImageReader imageReader = SystemImage.reader();
-             if (imageReader != null) {
-                 return imageReader.findLocation(module, name);
-             } else {
-                 // not an images build
-                 return null;
-             }
-         }
- 
          /**
           * Returns {@code true} if the given resource exists, {@code false}
           * if not found.
           */
-         private boolean containsImageLocation(String name) throws IOException {
-             Objects.requireNonNull(name);
+         private boolean containsResource(String resourcePath) throws IOException {
+             Objects.requireNonNull(resourcePath);
              if (closed)
                  throw new IOException("ModuleReader is closed");
              ImageReader imageReader = SystemImage.reader();
              if (imageReader != null) {
-                 return imageReader.verifyLocation(module, name);
+                 ImageReader.Node node = imageReader.findNode("/modules" + resourcePath);
+                 return node != null && node.isResource();
              } else {
                  // not an images build
                  return false;
              }
          }
  
          @Override
          public Optional<URI> find(String name) throws IOException {
-             if (containsImageLocation(name)) {
-                 URI u = JNUA.create("jrt", "/" + module + "/" + name);
+             String resourcePath = "/" + module + "/" + name;
+             if (containsResource(resourcePath)) {
+                 URI u = JNUA.create("jrt", resourcePath);
                  return Optional.of(u);
              } else {
                  return Optional.empty();
              }
          }

@@ -440,18 +453,29 @@
              } finally {
                  release(bb);
              }
          }
  
+         /**
+          * Returns the node for the given resource if found. If the name references
+          * a non-resource node, then {@code null} is returned.
+          */
+         private ImageReader.Node findResource(ImageReader reader, String name) throws IOException {
+             Objects.requireNonNull(name);
+             if (closed) {
+                 throw new IOException("ModuleReader is closed");
+             }
+             String nodeName = "/modules/" + module + "/" + name;
+             ImageReader.Node node = reader.findNode(nodeName);
+             return (node != null && node.isResource()) ? node : null;
+         }
+ 
          @Override
          public Optional<ByteBuffer> read(String name) throws IOException {
-             ImageLocation location = findImageLocation(name);
-             if (location != null) {
-                 return Optional.of(SystemImage.reader().getResourceBuffer(location));
-             } else {
-                 return Optional.empty();
-             }
+             ImageReader reader = SystemImage.reader();
+             return Optional.ofNullable(findResource(reader, name))
+                     .map(reader::getResourceBuffer);
          }
  
          @Override
          public void release(ByteBuffer bb) {
              Objects.requireNonNull(bb);

@@ -479,11 +503,11 @@
       * run-time image.
       */
      private static class ModuleContentSpliterator implements Spliterator<String> {
          final String moduleRoot;
          final Deque<ImageReader.Node> stack;
-         Iterator<ImageReader.Node> iterator;
+         Iterator<String> iterator;
  
          ModuleContentSpliterator(String module) throws IOException {
              moduleRoot = "/modules/" + module;
              stack = new ArrayDeque<>();
  

@@ -500,17 +524,14 @@
           * there are no remaining nodes to visit.
           */
          private String next() throws IOException {
              for (;;) {
                  while (iterator.hasNext()) {
-                     ImageReader.Node node = iterator.next();
-                     String name = node.getName();
+                     String name = iterator.next();
+                     ImageReader.Node node = SystemImage.reader().findNode(name);
                      if (node.isDirectory()) {
-                         // build node
-                         ImageReader.Node dir = SystemImage.reader().findNode(name);
-                         assert dir.isDirectory();
-                         stack.push(dir);
+                         stack.push(node);
                      } else {
                          // strip /modules/$MODULE/ prefix
                          return name.substring(moduleRoot.length() + 1);
                      }
                  }

@@ -518,11 +539,11 @@
                  if (stack.isEmpty()) {
                      return null;
                  } else {
                      ImageReader.Node dir = stack.poll();
                      assert dir.isDirectory();
-                     iterator = dir.getChildren().iterator();
+                     iterator = dir.getChildNames().iterator();
                  }
              }
          }
  
          @Override
< prev index next >