This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new 008d0b4d5b Add `getModuleName(Path)` and `getModuleDescription(Path)` 
methods in `DependencyResolverResult`. (#1625)
008d0b4d5b is described below

commit 008d0b4d5b3640f372e72587d2be42dde498b5b8
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Fri Aug 16 11:19:34 2024 +0200

    Add `getModuleName(Path)` and `getModuleDescription(Path)` methods in 
`DependencyResolverResult`. (#1625)
    
    Those methods are helpful for plugins that need to provide `--add-reads` 
and similar options,
    as they allow to reuse the cached values instead of decoding 
`module-info.class` many times.
---
 .../api/services/DependencyResolverResult.java     | 35 +++++++++++
 .../impl/DefaultDependencyResolverResult.java      | 49 +++++++++++----
 .../maven/internal/impl/PathModularization.java    | 73 ++++++----------------
 3 files changed, 93 insertions(+), 64 deletions(-)

diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
index e7ab86d011..c8f125eb7e 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
@@ -18,12 +18,15 @@
  */
 package org.apache.maven.api.services;
 
+import java.io.IOException;
+import java.lang.module.ModuleDescriptor;
 import java.nio.file.Path;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
 import org.apache.maven.api.Dependency;
+import org.apache.maven.api.DependencyScope;
 import org.apache.maven.api.JavaPathType;
 import org.apache.maven.api.Node;
 import org.apache.maven.api.PathType;
@@ -100,6 +103,38 @@ public interface DependencyResolverResult {
     @Nonnull
     Map<Dependency, Path> getDependencies();
 
+    /**
+     * Returns the Java module name of the dependency at the given path.
+     * The given dependency should be one of the paths returned by {@link 
#getDependencies()}.
+     * The module name is extracted from the {@code module-info.class} file if 
present, otherwise from
+     * the {@code "Automatic-Module-Name"} attribute of the {@code 
META-INF/MANIFEST.MF} file if present.
+     *
+     * <p>A typical usage is to invoke this method for all dependencies having 
a
+     * {@link DependencyScope#TEST TEST} or {@link DependencyScope#TEST_ONLY 
TEST_ONLY}
+     * {@linkplain Dependency#getScope() scope}. An {@code --add-reads} option 
may need
+     * to be generated for compiling and running the test classes that use 
such dependencies.</p>
+     *
+     * @param dependency path to the dependency for which to get the module 
name
+     * @return module name of the dependency at the given path, or empty if 
the dependency is not modular
+     * @throws IOException if the module information of the specified 
dependency cannot be read
+     */
+    Optional<String> getModuleName(@Nonnull Path dependency) throws 
IOException;
+
+    /**
+     * Returns the Java module descriptor of the dependency at the given path.
+     * The given dependency should be one of the paths returned by {@link 
#getDependencies()}.
+     * The module descriptor is extracted from the {@code module-info.class} 
file if present.
+     *
+     * <p>{@link #getModuleName(Path)} is preferred when only the module name 
is desired,
+     * because a name may be present even if the descriptor is absent. This 
method is for
+     * cases when more information is desired, such as the set of exported 
packages.</p>
+     *
+     * @param dependency path to the dependency for which to get the module 
name
+     * @return module name of the dependency at the given path, or empty if 
the dependency is not modular
+     * @throws IOException if the module information of the specified 
dependency cannot be read
+     */
+    Optional<ModuleDescriptor> getModuleDescriptor(@Nonnull Path dependency) 
throws IOException;
+
     /**
      * If the module-path contains at least one filename-based auto-module, 
prepares a warning message.
      * The module path is the collection of dependencies associated to {@link 
JavaPathType#MODULES}.
diff --git 
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java
 
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java
index ffad2adab5..be6a8cbb3a 100644
--- 
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java
+++ 
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java
@@ -19,6 +19,7 @@
 package org.apache.maven.internal.impl;
 
 import java.io.IOException;
+import java.lang.module.ModuleDescriptor;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -154,7 +155,7 @@ class DefaultDependencyResolverResult implements 
DependencyResolverResult {
      * @param test the test output directory, or {@code null} if none
      * @throws IOException if an error occurred while reading module 
information
      *
-     * TODO: this is currently not called
+     * TODO: this is currently not called. This is intended for use by 
Surefire and may move there.
      */
     void addOutputDirectory(Path main, Path test) throws IOException {
         if (outputModules != null) {
@@ -169,8 +170,9 @@ class DefaultDependencyResolverResult implements 
DependencyResolverResult {
         if (test != null) {
             boolean addToClasspath = true;
             PathModularization testModules = cache.getModuleInfo(test);
-            boolean isModuleHierarchy = outputModules.isModuleHierarchy() || 
testModules.isModuleHierarchy();
-            for (String moduleName : outputModules.getModuleNames().values()) {
+            boolean isModuleHierarchy = outputModules.isModuleHierarchy || 
testModules.isModuleHierarchy;
+            for (Object value : outputModules.descriptors.values()) {
+                String moduleName = name(value);
                 Path subdir = test;
                 if (isModuleHierarchy) {
                     // If module hierarchy is used, the directory names shall 
be the module names.
@@ -189,8 +191,8 @@ class DefaultDependencyResolverResult implements 
DependencyResolverResult {
              * If the test output directory provides some modules of its own, 
add them.
              * Except for this unusual case, tests should never be added to 
the module-path.
              */
-            for (Map.Entry<Path, String> entry : 
testModules.getModuleNames().entrySet()) {
-                if (!outputModules.containsModule(entry.getValue())) {
+            for (Map.Entry<Path, Object> entry : 
testModules.descriptors.entrySet()) {
+                if (!outputModules.containsModule(name(entry.getValue()))) {
                     addPathElement(JavaPathType.MODULES, entry.getKey());
                     addToClasspath = false;
                 }
@@ -246,9 +248,9 @@ class DefaultDependencyResolverResult implements 
DependencyResolverResult {
                 outputModules = PathModularization.NONE;
             }
             PathType type = null;
-            for (Map.Entry<Path, String> info :
-                    cache.getModuleInfo(path).getModuleNames().entrySet()) {
-                String moduleName = info.getValue();
+            for (Map.Entry<Path, Object> info :
+                    cache.getModuleInfo(path).descriptors.entrySet()) {
+                String moduleName = name(info.getValue());
                 type = JavaPathType.patchModule(moduleName);
                 if (!containsModule(moduleName)) {
                     /*
@@ -269,9 +271,9 @@ class DefaultDependencyResolverResult implements 
DependencyResolverResult {
             if (type == null) {
                 Path main = findArtifactPath(dep.getGroupId(), 
dep.getArtifactId());
                 if (main != null) {
-                    for (Map.Entry<Path, String> info :
-                            
cache.getModuleInfo(main).getModuleNames().entrySet()) {
-                        type = JavaPathType.patchModule(info.getValue());
+                    for (Map.Entry<Path, Object> info :
+                            cache.getModuleInfo(main).descriptors.entrySet()) {
+                        type = JavaPathType.patchModule(name(info.getValue()));
                         addPathElement(type, info.getKey());
                         // There is usually no more than one element, but 
nevertheless allow multi-modules.
                     }
@@ -360,6 +362,31 @@ class DefaultDependencyResolverResult implements 
DependencyResolverResult {
         return dependencies;
     }
 
+    @Override
+    public Optional<ModuleDescriptor> getModuleDescriptor(Path dependency) 
throws IOException {
+        Object value = 
cache.getModuleInfo(dependency).descriptors.get(dependency);
+        return (value instanceof ModuleDescriptor) ? 
Optional.of((ModuleDescriptor) value) : Optional.empty();
+    }
+
+    @Override
+    public Optional<String> getModuleName(Path dependency) throws IOException {
+        return Optional.ofNullable(
+                
name(cache.getModuleInfo(dependency).descriptors.get(dependency)));
+    }
+
+    /**
+     * Returns the module name for the given value of the {@link 
PathModularization#descriptors} map.
+     */
+    private static String name(final Object value) {
+        if (value instanceof String) {
+            return (String) value;
+        } else if (value instanceof ModuleDescriptor) {
+            return ((ModuleDescriptor) value).name();
+        } else {
+            return null;
+        }
+    }
+
     @Override
     public Optional<String> warningForFilenameBasedAutomodules() {
         try {
diff --git 
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java
 
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java
index 2728fb4aca..d8e9e941dd 100644
--- 
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java
+++ 
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java
@@ -70,23 +70,24 @@ class PathModularization {
      * It may however contain more than one entry if module hierarchy was 
detected,
      * in which case there is one key per sub-directory.
      *
+     * <p>Values are instances of either {@link ModuleDescriptor} or {@link 
String}.
+     * The latter case happens when a JAR file has no {@code 
module-info.class} entry
+     * but has an automatic name declared in {@code META-INF/MANIFEST.MF}.</p>
+     *
      * <p>This map may contain null values if the constructor was invoked with 
{@code resolve}
      * parameter set to false. This is more efficient when only the module 
existence needs to
      * be tested, and module descriptors are not needed.</p>
-     *
-     * @see #getModuleNames()
      */
-    private final Map<Path, String> descriptors;
+    @Nonnull
+    final Map<Path, Object> descriptors;
 
     /**
      * Whether module hierarchy was detected. If false, then package hierarchy 
is assumed.
      * In a package hierarchy, the {@linkplain #descriptors} map has either 
zero or one entry.
      * In a module hierarchy, the descriptors map may have an arbitrary number 
of entries,
      * including one (so the map size cannot be used as a criterion).
-     *
-     * @see #isModuleHierarchy()
      */
-    private final boolean isModuleHierarchy;
+    final boolean isModuleHierarchy;
 
     /**
      * Constructs an empty instance for non-modular dependencies.
@@ -144,13 +145,13 @@ class PathModularization {
              */
             Path file = path.resolve(MODULE_INFO);
             if (Files.isRegularFile(file)) {
-                String name = null;
+                ModuleDescriptor descriptor = null;
                 if (resolve) {
                     try (InputStream in = Files.newInputStream(file)) {
-                        name = getModuleName(in);
+                        descriptor = ModuleDescriptor.read(in);
                     }
                 }
-                descriptors = Collections.singletonMap(file, name);
+                descriptors = Collections.singletonMap(file, descriptor);
                 isModuleHierarchy = false;
                 return;
             }
@@ -160,27 +161,27 @@ class PathModularization {
              * source files.
              */
             if (Files.isDirectory(file)) {
-                Map<Path, String> names = new HashMap<>();
+                var multi = new HashMap<Path, ModuleDescriptor>();
                 try (Stream<Path> subdirs = Files.list(file)) {
                     subdirs.filter(Files::isDirectory).forEach((subdir) -> {
                         Path mf = subdir.resolve(MODULE_INFO);
                         if (Files.isRegularFile(mf)) {
-                            String name = null;
+                            ModuleDescriptor descriptor = null;
                             if (resolve) {
                                 try (InputStream in = 
Files.newInputStream(mf)) {
-                                    name = getModuleName(in);
+                                    descriptor = ModuleDescriptor.read(in);
                                 } catch (IOException e) {
                                     throw new UncheckedIOException(e);
                                 }
                             }
-                            names.put(mf, name);
+                            multi.put(mf, descriptor);
                         }
                     });
                 } catch (UncheckedIOException e) {
                     throw e.getCause();
                 }
-                if (!names.isEmpty()) {
-                    descriptors = Collections.unmodifiableMap(names);
+                if (!multi.isEmpty()) {
+                    descriptors = Collections.unmodifiableMap(multi);
                     isModuleHierarchy = true;
                     return;
                 }
@@ -194,13 +195,13 @@ class PathModularization {
             try (JarFile jar = new JarFile(path.toFile())) {
                 ZipEntry entry = jar.getEntry(MODULE_INFO);
                 if (entry != null) {
-                    String name = null;
+                    ModuleDescriptor descriptor = null;
                     if (resolve) {
                         try (InputStream in = jar.getInputStream(entry)) {
-                            name = getModuleName(in);
+                            descriptor = ModuleDescriptor.read(in);
                         }
                     }
-                    descriptors = Collections.singletonMap(path, name);
+                    descriptors = Collections.singletonMap(path, descriptor);
                     isModuleHierarchy = false;
                     return;
                 }
@@ -209,7 +210,7 @@ class PathModularization {
                 if (mf != null) {
                     Object name = mf.getMainAttributes().get(AUTO_MODULE_NAME);
                     if (name instanceof String) {
-                        descriptors = Collections.singletonMap(path, (String) 
name);
+                        descriptors = Collections.singletonMap(path, name);
                         isModuleHierarchy = false;
                         return;
                     }
@@ -220,15 +221,6 @@ class PathModularization {
         isModuleHierarchy = false;
     }
 
-    /**
-     * {@return the module name declared in the given {@code module-info} 
descriptor}.
-     * The input stream may be for a file or for an entry in a JAR file.
-     */
-    @Nonnull
-    private static String getModuleName(InputStream in) throws IOException {
-        return ModuleDescriptor.read(in).name();
-    }
-
     /**
      * {@return the type of path detected}. The return value is {@link 
JavaPathType#MODULES}
      * if the dependency is a modular JAR file or a directory containing 
module descriptor(s),
@@ -253,31 +245,6 @@ class PathModularization {
         }
     }
 
-    /**
-     * {@return whether module hierarchy was detected}. If {@code false}, then 
package hierarchy is assumed.
-     * In a package hierarchy, the {@linkplain #getModuleNames()} map of 
modules has either zero or one entry.
-     * In a module hierarchy, the descriptors map may have an arbitrary number 
of entries,
-     * including one (so the map size cannot be used as a criterion).
-     */
-    public boolean isModuleHierarchy() {
-        return isModuleHierarchy;
-    }
-
-    /**
-     * {@return the module names for the path specified at construction time}.
-     * This map is usually either empty if no module was found, or a singleton 
map.
-     * It may however contain more than one entry if module hierarchy was 
detected,
-     * in which case there is one key per sub-directory.
-     *
-     * <p>This map may contain null values if the constructor was invoked with 
{@code resolve}
-     * parameter set to false. This is more efficient when only the module 
existence needs to
-     * be tested, and module descriptors are not needed.</p>
-     */
-    @Nonnull
-    public Map<Path, String> getModuleNames() {
-        return descriptors;
-    }
-
     /**
      * {@return whether the dependency contains a module of the given name}.
      */

Reply via email to