[ 
https://issues.apache.org/jira/browse/MNG-8015?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17807623#comment-17807623
 ] 

ASF GitHub Bot commented on MNG-8015:
-------------------------------------

gnodet commented on code in PR #1378:
URL: https://github.com/apache/maven/pull/1378#discussion_r1453039589


##########
api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java:
##########
@@ -33,27 +36,226 @@
 @Immutable
 public interface DependencyProperties {
     /**
-     * Boolean flag telling that dependency contains all of its dependencies. 
Value of this key should be parsed with
-     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * Keys in the dependency properties map.
+     * Each key can be associated to values of a specific class.
+     *
+     * @param  <V>  type of value associated to the key
+     */
+    class Key<V> {
+        /**
+         * The keys that are defined in this {@code DependencyProperties} map.
+         * Accesses to this map shall be synchronized on the map.
+         *
+         * @see #intern()
+         */
+        private static final Map<String, Key<?>> INTERNS = new HashMap<>();

Review Comment:
   Can we use a `ConcurrentHashMap` rather than a `HashMap` and synchronizing 
access to it ?



##########
api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java:
##########
@@ -33,27 +36,226 @@
 @Immutable
 public interface DependencyProperties {
     /**
-     * Boolean flag telling that dependency contains all of its dependencies. 
Value of this key should be parsed with
-     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * Keys in the dependency properties map.
+     * Each key can be associated to values of a specific class.
+     *
+     * @param  <V>  type of value associated to the key
+     */
+    class Key<V> {
+        /**
+         * The keys that are defined in this {@code DependencyProperties} map.
+         * Accesses to this map shall be synchronized on the map.
+         *
+         * @see #intern()
+         */
+        private static final Map<String, Key<?>> INTERNS = new HashMap<>();
+
+        /**
+         * Value returned by {@link #name()}.
+         */
+        @Nonnull
+        private final String name;
+
+        /**
+         * Value returned by {@link #valueType()}.
+         */
+        @Nonnull
+        private final Class<V> valueType;
+
+        /**
+         * Creates a new key.
+         *
+         * @param name name of the key
+         * @param valueType type of value associated to the key
+         */
+        public Key(@Nonnull final String name, @Nonnull final Class<V> 
valueType) {
+            this.name = Objects.requireNonNull(name);
+            this.valueType = Objects.requireNonNull(valueType);
+        }
+
+        /**
+         * If a key exists in the {@linkplain #intern() intern pool} for the 
given name, returns that key.
+         * Otherwise, if the {@code defaultType} is non-null, creates a key 
for values of the specified type.
+         * Otherwise, returns {@code null}.
+         *
+         * @param name name of the key to search or create
+         * @param defaultType value type of the key to create if none exist 
for the given name, or {@code null}
+         * @return key found or created, or {@code null} if no key was found 
and {@code defaultType} is null
+         *
+         * @see #intern()
+         */
+        public static Key<?> forName(String name, Class<?> defaultType) {
+            Key<?> key;
+            synchronized (INTERNS) {
+                key = INTERNS.get(name);
+            }
+            if (key == null && defaultType != null) {
+                key = new Key<>(name, defaultType);
+            }
+            return key;
+        }
+
+        /**
+         * {@return the name of the key}.
+         */
+        @Nonnull
+        public String name() {
+            return name;
+        }
+
+        /**
+         * {@return the type of value associated to the key}.
+         */
+        @Nonnull
+        public Class<V> valueType() {
+            return valueType;
+        }
+
+        /**
+         * {@return a canonical representation of this key}. A pool of keys, 
initially empty, is maintained privately.
+         * When the {@code intern()} method is invoked, if the pool already 
contains a key equal to this {@code Key}
+         * as determined by the {@link #equals(Object)} method, then the key 
from the pool is returned. Otherwise,
+         * if no key exist in the pool for this key {@linkplain #name() name}, 
then this {@code Key} object is added
+         * to the pool and {@code this} is returned. Otherwise an {@link 
IllegalStateException} is thrown.
+         *
+         * @throws IllegalStateException if a key exists in the pool for the 
same name but a different class of values.
+         *
+         * @see String#intern()
+         */
+        @SuppressWarnings("unchecked")
+        public Key<V> intern() {
+            Key<?> previous;
+            synchronized (INTERNS) {
+                previous = INTERNS.putIfAbsent(name, this);
+            }
+            if (previous == null) {
+                return this;
+            }
+            if (equals(previous)) {
+                return (Key<V>) previous;
+            }
+            throw new IllegalStateException("Key " + name + " already exists 
for a different class of values.");
+        }
+
+        /**
+         * {@return a string representation of this key}.
+         * By default, this is the name of this key.
+         */
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        /**
+         * {@return an hash code value for this key}.
+         */
+        @Override
+        public int hashCode() {
+            return 7 + name.hashCode() + 31 * valueType.hashCode();

Review Comment:
   `Objects.hash(name, valueType)`



##########
api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java:
##########
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The option of a Java command-line tool where to place the paths to some 
dependencies.
+ * A {@code PathType} can identify the class-path, the module-path, the 
patches for a specific module,
+ * or another kind of path. This class is like an enumeration, except that it 
is extensible:
+ * plugins can define their own kinds of path.
+ *
+ * <p>One path type is handled in a special way: contrarily to other options,
+ * the paths specified in a {@code --patch-module} Java option is effective 
only for a specified module.
+ * This type is created by calls to {@link #patchModule(String)} and a new 
instance must be created for
+ * every module to patch.</p>
+ *
+ * <p>Path types are often exclusive. For example, a dependency should not be 
both on the Java class-path
+ * and on the Java module-path.</p>
+ *
+ * @see 
org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths()
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public final class JavaPathType extends PathType {
+    /**
+     * The path identified by the Java {@code --class-path} option.
+     * Used for compilation, execution and Javadoc among others.
+     *
+     * <h4>Context-sensitive interpretation</h4>
+     * A dependency with this path type will not necessarily be placed on the 
class-path.
+     * There is two circumstances where the dependency may be nevertheless 
placed somewhere else:
+     *
+     * <ul>
+     *   <li>If {@link #MODULES} path type is also set, then the dependency 
can be placed either on the
+     *       class-path or on the module-path, but only one of those. The 
choice is up to the plugin,
+     *       possibly using heuristic rules (Maven 3 behavior).</li>
+     *   <li>If a {@link #patchModule(String)} is also set and the main JAR 
file was placed on the module-path,
+     *       then the test dependency will be placed on the Java {@code 
--patch-module} option instead of the
+     *       class-path.</li>
+     * </ul>
+     */
+    public static final JavaPathType CLASSES = new JavaPathType("CLASSES", 
"--class-path", null);
+
+    /**
+     * The path identified by the Java {@code --module-path} option.
+     * Used for compilation, execution and Javadoc among others.
+     *
+     * <h4>Context-sensitive interpretation</h4>
+     * A dependency with this flag will not necessarily be placed on the 
module-path.
+     * There is two circumstances where the dependency may be nevertheless 
placed somewhere else:
+     *
+     * <ul>
+     *   <li>If {@link #CLASSES} path type is also set, then the dependency 
<em>should</em> be placed on the
+     *       module-path, but is nevertheless compatible with placement on the 
class-path. Compatibility can

Review Comment:
   `nevertheless` -> `also`



##########
api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java:
##########
@@ -33,27 +36,226 @@
 @Immutable
 public interface DependencyProperties {
     /**
-     * Boolean flag telling that dependency contains all of its dependencies. 
Value of this key should be parsed with
-     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * Keys in the dependency properties map.
+     * Each key can be associated to values of a specific class.
+     *
+     * @param  <V>  type of value associated to the key
+     */
+    class Key<V> {
+        /**
+         * The keys that are defined in this {@code DependencyProperties} map.
+         * Accesses to this map shall be synchronized on the map.
+         *
+         * @see #intern()
+         */
+        private static final Map<String, Key<?>> INTERNS = new HashMap<>();
+
+        /**
+         * Value returned by {@link #name()}.
+         */
+        @Nonnull
+        private final String name;
+
+        /**
+         * Value returned by {@link #valueType()}.
+         */
+        @Nonnull
+        private final Class<V> valueType;
+
+        /**
+         * Creates a new key.
+         *
+         * @param name name of the key
+         * @param valueType type of value associated to the key
+         */
+        public Key(@Nonnull final String name, @Nonnull final Class<V> 
valueType) {
+            this.name = Objects.requireNonNull(name);
+            this.valueType = Objects.requireNonNull(valueType);
+        }
+
+        /**
+         * If a key exists in the {@linkplain #intern() intern pool} for the 
given name, returns that key.
+         * Otherwise, if the {@code defaultType} is non-null, creates a key 
for values of the specified type.
+         * Otherwise, returns {@code null}.
+         *
+         * @param name name of the key to search or create
+         * @param defaultType value type of the key to create if none exist 
for the given name, or {@code null}
+         * @return key found or created, or {@code null} if no key was found 
and {@code defaultType} is null
+         *
+         * @see #intern()
+         */
+        public static Key<?> forName(String name, Class<?> defaultType) {
+            Key<?> key;
+            synchronized (INTERNS) {
+                key = INTERNS.get(name);
+            }
+            if (key == null && defaultType != null) {
+                key = new Key<>(name, defaultType);
+            }
+            return key;
+        }
+
+        /**
+         * {@return the name of the key}.
+         */
+        @Nonnull
+        public String name() {
+            return name;
+        }
+
+        /**
+         * {@return the type of value associated to the key}.
+         */
+        @Nonnull
+        public Class<V> valueType() {
+            return valueType;
+        }
+
+        /**
+         * {@return a canonical representation of this key}. A pool of keys, 
initially empty, is maintained privately.
+         * When the {@code intern()} method is invoked, if the pool already 
contains a key equal to this {@code Key}
+         * as determined by the {@link #equals(Object)} method, then the key 
from the pool is returned. Otherwise,
+         * if no key exist in the pool for this key {@linkplain #name() name}, 
then this {@code Key} object is added
+         * to the pool and {@code this} is returned. Otherwise an {@link 
IllegalStateException} is thrown.
+         *
+         * @throws IllegalStateException if a key exists in the pool for the 
same name but a different class of values.
+         *
+         * @see String#intern()
+         */
+        @SuppressWarnings("unchecked")
+        public Key<V> intern() {
+            Key<?> previous;
+            synchronized (INTERNS) {
+                previous = INTERNS.putIfAbsent(name, this);
+            }
+            if (previous == null) {
+                return this;
+            }
+            if (equals(previous)) {
+                return (Key<V>) previous;
+            }
+            throw new IllegalStateException("Key " + name + " already exists 
for a different class of values.");
+        }
+
+        /**
+         * {@return a string representation of this key}.
+         * By default, this is the name of this key.
+         */
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        /**
+         * {@return an hash code value for this key}.
+         */
+        @Override
+        public int hashCode() {
+            return 7 + name.hashCode() + 31 * valueType.hashCode();
+        }
+
+        /**
+         * Compares this key with the given object for equality.
+         * Two keys are considered equal if they have the same name
+         * and are associated to values of the same class.
+         *
+         * @param obj the object to compare with this key
+         * @return whether the given object is equal to this key
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj != null && getClass() == obj.getClass()) {
+                final Key<?> other = (Key<?>) obj;
+                return name.equals(other.name) && 
valueType.equals(other.valueType);
+            }
+            return false;
+        }
+    }
+
+    /**
+     * The dependency type. The {@linkplain Key#name() name} of this property
+     * is equal to the {@code ArtifactProperties.TYPE} value.
+     */
+    Key<String> TYPE = new Key<>("type", String.class).intern();
+
+    /**
+     * The dependency language. The {@linkplain Key#name() name} of this 
property
+     * is equal to the {@code ArtifactProperties.LANGUAGE} value.
+     */
+    Key<String> LANGUAGE = new Key<>("language", String.class).intern();
+
+    /**
+     * Types of path (class-path, module-path, …) where the dependency can be 
placed.
+     * For most deterministic builds, the array length should be 1. In such 
case,
+     * the dependency will be unconditionally placed on the specified type of 
path
+     * and no heuristic rule will be involved.
+     *
+     * <p>It is nevertheless common to specify two or more types of path. For 
example,
+     * a Java library may be compatible with either the class-path or the 
module-path,
+     * and the user may have provided no instruction about which type to use. 
In such
+     * case, the plugin may apply rules for choosing a path. See for example
+     * {@link JavaPathType#CLASSES} and {@link JavaPathType#MODULES}.</p>
+     */
+    Key<PathType[]> PATH_TYPES = new Key<>("pathTypes", 
PathType[].class).intern();
+
+    /**
+     * Boolean flag telling that dependency contains all of its dependencies.
      * <p>
      * <em>Important: this flag must be kept in sync with resolver! (as is 
used during collection)</em>
      */
-    String FLAG_INCLUDES_DEPENDENCIES = "includesDependencies";
+    Key<Boolean> FLAG_INCLUDES_DEPENDENCIES = new 
Key<>("includesDependencies", Boolean.class).intern();
 
     /**
-     * Boolean flag telling that dependency is meant to be placed on class 
path. Value of this key should be parsed with
-     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * Boolean flag telling that dependency is meant to be placed on class 
path.
+     *
+     * @deprecated Use {@link #PATH_TYPES} and {@link JavaPathType#CLASSES} 
instead.
      */
-    String FLAG_CLASS_PATH_CONSTITUENT = "classPathConstituent";
+    @Deprecated
+    Key<Boolean> FLAG_CLASS_PATH_CONSTITUENT = new 
Key<>("classPathConstituent", Boolean.class).intern();
 
     /**
-     * Returns immutable "map view" of all the properties.
+     * {@return the keys of all properties in this map}.
      */
-    @Nonnull
-    Map<String, String> asMap();
+    Set<Key<?>> keys();
+
+    /**
+     * Returns the value associated to the given key.
+     *
+     * @param <V> type of value to get
+     * @param key key of the value to get
+     * @return value associated to the given key, or {@code null} if none
+     */
+    <V> V get(@Nonnull Key<V> key);
+
+    /**
+     * Returns the value associated to the given key, or the given default 
value if none.
+     *
+     * @param <V> type of value to get
+     * @param key key of the value to get
+     * @param defaultValue the value to return is none is associated to the 
given key, or {@code null}
+     * @return value associated to the given key, or {@code null} if none and 
the default is null
+     */
+    <V> V getOrDefault(@Nonnull Key<V> key, V defaultValue);

Review Comment:
   Missing `@Nullable` on the return value and the `V` parameter to be explicit 
.



##########
api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java:
##########
@@ -33,27 +36,226 @@
 @Immutable
 public interface DependencyProperties {
     /**
-     * Boolean flag telling that dependency contains all of its dependencies. 
Value of this key should be parsed with
-     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * Keys in the dependency properties map.
+     * Each key can be associated to values of a specific class.
+     *
+     * @param  <V>  type of value associated to the key
+     */
+    class Key<V> {
+        /**
+         * The keys that are defined in this {@code DependencyProperties} map.
+         * Accesses to this map shall be synchronized on the map.
+         *
+         * @see #intern()
+         */
+        private static final Map<String, Key<?>> INTERNS = new HashMap<>();
+
+        /**
+         * Value returned by {@link #name()}.
+         */
+        @Nonnull
+        private final String name;
+
+        /**
+         * Value returned by {@link #valueType()}.
+         */
+        @Nonnull
+        private final Class<V> valueType;
+
+        /**
+         * Creates a new key.
+         *
+         * @param name name of the key
+         * @param valueType type of value associated to the key
+         */
+        public Key(@Nonnull final String name, @Nonnull final Class<V> 
valueType) {

Review Comment:
   `final` in parameters is useless, please remove



##########
api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java:
##########
@@ -33,27 +36,226 @@
 @Immutable
 public interface DependencyProperties {
     /**
-     * Boolean flag telling that dependency contains all of its dependencies. 
Value of this key should be parsed with
-     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * Keys in the dependency properties map.
+     * Each key can be associated to values of a specific class.
+     *
+     * @param  <V>  type of value associated to the key
+     */
+    class Key<V> {
+        /**
+         * The keys that are defined in this {@code DependencyProperties} map.
+         * Accesses to this map shall be synchronized on the map.
+         *
+         * @see #intern()
+         */
+        private static final Map<String, Key<?>> INTERNS = new HashMap<>();
+
+        /**
+         * Value returned by {@link #name()}.
+         */
+        @Nonnull
+        private final String name;
+
+        /**
+         * Value returned by {@link #valueType()}.
+         */
+        @Nonnull
+        private final Class<V> valueType;
+
+        /**
+         * Creates a new key.
+         *
+         * @param name name of the key
+         * @param valueType type of value associated to the key
+         */
+        public Key(@Nonnull final String name, @Nonnull final Class<V> 
valueType) {
+            this.name = Objects.requireNonNull(name);
+            this.valueType = Objects.requireNonNull(valueType);
+        }
+
+        /**
+         * If a key exists in the {@linkplain #intern() intern pool} for the 
given name, returns that key.
+         * Otherwise, if the {@code defaultType} is non-null, creates a key 
for values of the specified type.
+         * Otherwise, returns {@code null}.
+         *
+         * @param name name of the key to search or create
+         * @param defaultType value type of the key to create if none exist 
for the given name, or {@code null}
+         * @return key found or created, or {@code null} if no key was found 
and {@code defaultType} is null
+         *
+         * @see #intern()
+         */
+        public static Key<?> forName(String name, Class<?> defaultType) {
+            Key<?> key;
+            synchronized (INTERNS) {
+                key = INTERNS.get(name);
+            }
+            if (key == null && defaultType != null) {
+                key = new Key<>(name, defaultType);
+            }
+            return key;
+        }
+
+        /**
+         * {@return the name of the key}.
+         */
+        @Nonnull
+        public String name() {
+            return name;
+        }
+
+        /**
+         * {@return the type of value associated to the key}.
+         */
+        @Nonnull
+        public Class<V> valueType() {
+            return valueType;
+        }
+
+        /**
+         * {@return a canonical representation of this key}. A pool of keys, 
initially empty, is maintained privately.
+         * When the {@code intern()} method is invoked, if the pool already 
contains a key equal to this {@code Key}
+         * as determined by the {@link #equals(Object)} method, then the key 
from the pool is returned. Otherwise,
+         * if no key exist in the pool for this key {@linkplain #name() name}, 
then this {@code Key} object is added
+         * to the pool and {@code this} is returned. Otherwise an {@link 
IllegalStateException} is thrown.
+         *
+         * @throws IllegalStateException if a key exists in the pool for the 
same name but a different class of values.
+         *
+         * @see String#intern()
+         */
+        @SuppressWarnings("unchecked")
+        public Key<V> intern() {

Review Comment:
   I don't think the whole `intern` thing is needed at all.
   I would suppose all references to `Key`s will be done using 
`DependencyProperties.XXX`, so I don't see a good use case for users to create 
duplicate instances.



##########
api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java:
##########
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The option of a Java command-line tool where to place the paths to some 
dependencies.
+ * A {@code PathType} can identify the class-path, the module-path, the 
patches for a specific module,
+ * or another kind of path. This class is like an enumeration, except that it 
is extensible:
+ * plugins can define their own kinds of path.
+ *
+ * <p>One path type is handled in a special way: contrarily to other options,
+ * the paths specified in a {@code --patch-module} Java option is effective 
only for a specified module.
+ * This type is created by calls to {@link #patchModule(String)} and a new 
instance must be created for
+ * every module to patch.</p>
+ *
+ * <p>Path types are often exclusive. For example, a dependency should not be 
both on the Java class-path
+ * and on the Java module-path.</p>
+ *
+ * @see 
org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths()
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public final class JavaPathType extends PathType {
+    /**
+     * The path identified by the Java {@code --class-path} option.
+     * Used for compilation, execution and Javadoc among others.
+     *
+     * <h4>Context-sensitive interpretation</h4>
+     * A dependency with this path type will not necessarily be placed on the 
class-path.
+     * There is two circumstances where the dependency may be nevertheless 
placed somewhere else:

Review Comment:
   `There is` -> `There are`
   `be nevertheless` -> `nevertheless be`



##########
api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java:
##########
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The option of a Java command-line tool where to place the paths to some 
dependencies.
+ * A {@code PathType} can identify the class-path, the module-path, the 
patches for a specific module,
+ * or another kind of path. This class is like an enumeration, except that it 
is extensible:
+ * plugins can define their own kinds of path.
+ *
+ * <p>One path type is handled in a special way: contrarily to other options,
+ * the paths specified in a {@code --patch-module} Java option is effective 
only for a specified module.
+ * This type is created by calls to {@link #patchModule(String)} and a new 
instance must be created for
+ * every module to patch.</p>
+ *
+ * <p>Path types are often exclusive. For example, a dependency should not be 
both on the Java class-path
+ * and on the Java module-path.</p>
+ *
+ * @see 
org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths()
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public final class JavaPathType extends PathType {
+    /**
+     * The path identified by the Java {@code --class-path} option.
+     * Used for compilation, execution and Javadoc among others.
+     *
+     * <h4>Context-sensitive interpretation</h4>
+     * A dependency with this path type will not necessarily be placed on the 
class-path.
+     * There is two circumstances where the dependency may be nevertheless 
placed somewhere else:
+     *
+     * <ul>
+     *   <li>If {@link #MODULES} path type is also set, then the dependency 
can be placed either on the
+     *       class-path or on the module-path, but only one of those. The 
choice is up to the plugin,
+     *       possibly using heuristic rules (Maven 3 behavior).</li>
+     *   <li>If a {@link #patchModule(String)} is also set and the main JAR 
file was placed on the module-path,

Review Comment:
   `was placed` -> `is placed`



##########
api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java:
##########
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The option of a Java command-line tool where to place the paths to some 
dependencies.
+ * A {@code PathType} can identify the class-path, the module-path, the 
patches for a specific module,
+ * or another kind of path. This class is like an enumeration, except that it 
is extensible:
+ * plugins can define their own kinds of path.
+ *
+ * <p>One path type is handled in a special way: contrarily to other options,

Review Comment:
   `contrarily to` -> `unlike`



##########
api/maven-api-core/src/main/java/org/apache/maven/api/Type.java:
##########
@@ -80,11 +129,16 @@ public interface Type {
     String getClassifier();
 
     /**
-     * Specifies if the artifact contains java classes and should be
-     * added to the classpath.
+     * Specifies if the artifact contains java classes and can be added to the 
classpath.
+     * Whether the artifact <em>should</em> be added to the classpath depends 
on other
+     * {@linkplain #getDependencyProperties() dependency properties}.
+     *
+     * @return if the artifact <em>can</em> be added to the class path
      *
-     * @return if the artifact should be added to the class path
+     * @deprecated A value of {@code true} does not mean that the dependency 
<em>should</em>
+     * be placed on the classpath. See {@link JavaPathType} instead for better 
analysis.
      */
+    @Deprecated

Review Comment:
   If deprecation is necessary, it should be noted that it will be removed 
before 4.0.0 GA. 



##########
api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The option of a command-line tool where to place the paths to some 
dependencies.
+ * A {@code PathType} can identify the Java class-path, the Java module-path,
+ * or another kind of path for another programming language for example.
+ * This class is like an enumeration, except that it is extensible:
+ * plugins can define their own kinds of path.
+ *
+ * <p>Path types are often exclusive. For example, a dependency should not be 
both
+ * on the Java class-path and on the Java module-path.</p>
+ *
+ * @see DependencyProperties#PATH_TYPES
+ * @see 
org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths()
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public abstract class PathType {

Review Comment:
   I'm not convinced we will ever have an implementation other than 
`JavaPathType`, in which case, both interfaces could be merged.  I'd also 
prefer an interface rather than an abstract class if that's possible.



##########
api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java:
##########
@@ -33,27 +36,226 @@
 @Immutable
 public interface DependencyProperties {
     /**
-     * Boolean flag telling that dependency contains all of its dependencies. 
Value of this key should be parsed with
-     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * Keys in the dependency properties map.
+     * Each key can be associated to values of a specific class.
+     *
+     * @param  <V>  type of value associated to the key
+     */
+    class Key<V> {
+        /**
+         * The keys that are defined in this {@code DependencyProperties} map.
+         * Accesses to this map shall be synchronized on the map.
+         *
+         * @see #intern()
+         */
+        private static final Map<String, Key<?>> INTERNS = new HashMap<>();
+
+        /**
+         * Value returned by {@link #name()}.
+         */
+        @Nonnull
+        private final String name;
+
+        /**
+         * Value returned by {@link #valueType()}.
+         */
+        @Nonnull
+        private final Class<V> valueType;
+
+        /**
+         * Creates a new key.
+         *
+         * @param name name of the key
+         * @param valueType type of value associated to the key
+         */
+        public Key(@Nonnull final String name, @Nonnull final Class<V> 
valueType) {
+            this.name = Objects.requireNonNull(name);
+            this.valueType = Objects.requireNonNull(valueType);
+        }
+
+        /**
+         * If a key exists in the {@linkplain #intern() intern pool} for the 
given name, returns that key.
+         * Otherwise, if the {@code defaultType} is non-null, creates a key 
for values of the specified type.
+         * Otherwise, returns {@code null}.
+         *
+         * @param name name of the key to search or create
+         * @param defaultType value type of the key to create if none exist 
for the given name, or {@code null}
+         * @return key found or created, or {@code null} if no key was found 
and {@code defaultType} is null
+         *
+         * @see #intern()
+         */
+        public static Key<?> forName(String name, Class<?> defaultType) {
+            Key<?> key;
+            synchronized (INTERNS) {
+                key = INTERNS.get(name);
+            }
+            if (key == null && defaultType != null) {
+                key = new Key<>(name, defaultType);
+            }
+            return key;
+        }
+
+        /**
+         * {@return the name of the key}.
+         */
+        @Nonnull
+        public String name() {
+            return name;
+        }
+
+        /**
+         * {@return the type of value associated to the key}.
+         */
+        @Nonnull
+        public Class<V> valueType() {
+            return valueType;
+        }
+
+        /**
+         * {@return a canonical representation of this key}. A pool of keys, 
initially empty, is maintained privately.
+         * When the {@code intern()} method is invoked, if the pool already 
contains a key equal to this {@code Key}
+         * as determined by the {@link #equals(Object)} method, then the key 
from the pool is returned. Otherwise,
+         * if no key exist in the pool for this key {@linkplain #name() name}, 
then this {@code Key} object is added
+         * to the pool and {@code this} is returned. Otherwise an {@link 
IllegalStateException} is thrown.
+         *
+         * @throws IllegalStateException if a key exists in the pool for the 
same name but a different class of values.
+         *
+         * @see String#intern()
+         */
+        @SuppressWarnings("unchecked")
+        public Key<V> intern() {
+            Key<?> previous;
+            synchronized (INTERNS) {
+                previous = INTERNS.putIfAbsent(name, this);
+            }
+            if (previous == null) {
+                return this;
+            }
+            if (equals(previous)) {
+                return (Key<V>) previous;
+            }
+            throw new IllegalStateException("Key " + name + " already exists 
for a different class of values.");
+        }
+
+        /**
+         * {@return a string representation of this key}.
+         * By default, this is the name of this key.
+         */
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        /**
+         * {@return an hash code value for this key}.
+         */
+        @Override
+        public int hashCode() {
+            return 7 + name.hashCode() + 31 * valueType.hashCode();
+        }
+
+        /**
+         * Compares this key with the given object for equality.
+         * Two keys are considered equal if they have the same name
+         * and are associated to values of the same class.
+         *
+         * @param obj the object to compare with this key
+         * @return whether the given object is equal to this key
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj != null && getClass() == obj.getClass()) {
+                final Key<?> other = (Key<?>) obj;
+                return name.equals(other.name) && 
valueType.equals(other.valueType);
+            }
+            return false;
+        }
+    }
+
+    /**
+     * The dependency type. The {@linkplain Key#name() name} of this property
+     * is equal to the {@code ArtifactProperties.TYPE} value.
+     */
+    Key<String> TYPE = new Key<>("type", String.class).intern();
+
+    /**
+     * The dependency language. The {@linkplain Key#name() name} of this 
property
+     * is equal to the {@code ArtifactProperties.LANGUAGE} value.
+     */
+    Key<String> LANGUAGE = new Key<>("language", String.class).intern();
+
+    /**
+     * Types of path (class-path, module-path, …) where the dependency can be 
placed.
+     * For most deterministic builds, the array length should be 1. In such 
case,
+     * the dependency will be unconditionally placed on the specified type of 
path
+     * and no heuristic rule will be involved.
+     *
+     * <p>It is nevertheless common to specify two or more types of path. For 
example,
+     * a Java library may be compatible with either the class-path or the 
module-path,
+     * and the user may have provided no instruction about which type to use. 
In such
+     * case, the plugin may apply rules for choosing a path. See for example
+     * {@link JavaPathType#CLASSES} and {@link JavaPathType#MODULES}.</p>
+     */
+    Key<PathType[]> PATH_TYPES = new Key<>("pathTypes", 
PathType[].class).intern();

Review Comment:
   `Collection<PathType>` so that we can ensure immutability ?



##########
api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java:
##########
@@ -33,27 +36,226 @@
 @Immutable
 public interface DependencyProperties {
     /**
-     * Boolean flag telling that dependency contains all of its dependencies. 
Value of this key should be parsed with
-     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * Keys in the dependency properties map.
+     * Each key can be associated to values of a specific class.
+     *
+     * @param  <V>  type of value associated to the key
+     */
+    class Key<V> {
+        /**
+         * The keys that are defined in this {@code DependencyProperties} map.
+         * Accesses to this map shall be synchronized on the map.
+         *
+         * @see #intern()
+         */
+        private static final Map<String, Key<?>> INTERNS = new HashMap<>();
+
+        /**
+         * Value returned by {@link #name()}.
+         */
+        @Nonnull
+        private final String name;
+
+        /**
+         * Value returned by {@link #valueType()}.
+         */
+        @Nonnull
+        private final Class<V> valueType;
+
+        /**
+         * Creates a new key.
+         *
+         * @param name name of the key
+         * @param valueType type of value associated to the key
+         */
+        public Key(@Nonnull final String name, @Nonnull final Class<V> 
valueType) {
+            this.name = Objects.requireNonNull(name);
+            this.valueType = Objects.requireNonNull(valueType);
+        }
+
+        /**
+         * If a key exists in the {@linkplain #intern() intern pool} for the 
given name, returns that key.
+         * Otherwise, if the {@code defaultType} is non-null, creates a key 
for values of the specified type.
+         * Otherwise, returns {@code null}.
+         *
+         * @param name name of the key to search or create
+         * @param defaultType value type of the key to create if none exist 
for the given name, or {@code null}
+         * @return key found or created, or {@code null} if no key was found 
and {@code defaultType} is null
+         *
+         * @see #intern()
+         */
+        public static Key<?> forName(String name, Class<?> defaultType) {
+            Key<?> key;
+            synchronized (INTERNS) {
+                key = INTERNS.get(name);
+            }
+            if (key == null && defaultType != null) {
+                key = new Key<>(name, defaultType);
+            }
+            return key;
+        }
+
+        /**
+         * {@return the name of the key}.
+         */
+        @Nonnull
+        public String name() {
+            return name;
+        }
+
+        /**
+         * {@return the type of value associated to the key}.
+         */
+        @Nonnull
+        public Class<V> valueType() {
+            return valueType;
+        }
+
+        /**
+         * {@return a canonical representation of this key}. A pool of keys, 
initially empty, is maintained privately.
+         * When the {@code intern()} method is invoked, if the pool already 
contains a key equal to this {@code Key}
+         * as determined by the {@link #equals(Object)} method, then the key 
from the pool is returned. Otherwise,
+         * if no key exist in the pool for this key {@linkplain #name() name}, 
then this {@code Key} object is added
+         * to the pool and {@code this} is returned. Otherwise an {@link 
IllegalStateException} is thrown.
+         *
+         * @throws IllegalStateException if a key exists in the pool for the 
same name but a different class of values.
+         *
+         * @see String#intern()
+         */
+        @SuppressWarnings("unchecked")
+        public Key<V> intern() {
+            Key<?> previous;
+            synchronized (INTERNS) {
+                previous = INTERNS.putIfAbsent(name, this);
+            }
+            if (previous == null) {
+                return this;
+            }
+            if (equals(previous)) {
+                return (Key<V>) previous;
+            }
+            throw new IllegalStateException("Key " + name + " already exists 
for a different class of values.");
+        }
+
+        /**
+         * {@return a string representation of this key}.
+         * By default, this is the name of this key.
+         */
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        /**
+         * {@return an hash code value for this key}.
+         */
+        @Override
+        public int hashCode() {
+            return 7 + name.hashCode() + 31 * valueType.hashCode();
+        }
+
+        /**
+         * Compares this key with the given object for equality.
+         * Two keys are considered equal if they have the same name
+         * and are associated to values of the same class.
+         *
+         * @param obj the object to compare with this key
+         * @return whether the given object is equal to this key
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj != null && getClass() == obj.getClass()) {
+                final Key<?> other = (Key<?>) obj;
+                return name.equals(other.name) && 
valueType.equals(other.valueType);
+            }
+            return false;
+        }
+    }
+
+    /**
+     * The dependency type. The {@linkplain Key#name() name} of this property
+     * is equal to the {@code ArtifactProperties.TYPE} value.
+     */
+    Key<String> TYPE = new Key<>("type", String.class).intern();
+
+    /**
+     * The dependency language. The {@linkplain Key#name() name} of this 
property
+     * is equal to the {@code ArtifactProperties.LANGUAGE} value.
+     */
+    Key<String> LANGUAGE = new Key<>("language", String.class).intern();
+
+    /**
+     * Types of path (class-path, module-path, …) where the dependency can be 
placed.
+     * For most deterministic builds, the array length should be 1. In such 
case,
+     * the dependency will be unconditionally placed on the specified type of 
path
+     * and no heuristic rule will be involved.
+     *
+     * <p>It is nevertheless common to specify two or more types of path. For 
example,
+     * a Java library may be compatible with either the class-path or the 
module-path,
+     * and the user may have provided no instruction about which type to use. 
In such
+     * case, the plugin may apply rules for choosing a path. See for example
+     * {@link JavaPathType#CLASSES} and {@link JavaPathType#MODULES}.</p>
+     */
+    Key<PathType[]> PATH_TYPES = new Key<>("pathTypes", 
PathType[].class).intern();
+
+    /**
+     * Boolean flag telling that dependency contains all of its dependencies.
      * <p>
      * <em>Important: this flag must be kept in sync with resolver! (as is 
used during collection)</em>
      */
-    String FLAG_INCLUDES_DEPENDENCIES = "includesDependencies";
+    Key<Boolean> FLAG_INCLUDES_DEPENDENCIES = new 
Key<>("includesDependencies", Boolean.class).intern();
 
     /**
-     * Boolean flag telling that dependency is meant to be placed on class 
path. Value of this key should be parsed with
-     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * Boolean flag telling that dependency is meant to be placed on class 
path.
+     *
+     * @deprecated Use {@link #PATH_TYPES} and {@link JavaPathType#CLASSES} 
instead.
      */
-    String FLAG_CLASS_PATH_CONSTITUENT = "classPathConstituent";
+    @Deprecated
+    Key<Boolean> FLAG_CLASS_PATH_CONSTITUENT = new 
Key<>("classPathConstituent", Boolean.class).intern();
 
     /**
-     * Returns immutable "map view" of all the properties.
+     * {@return the keys of all properties in this map}.
      */
-    @Nonnull
-    Map<String, String> asMap();
+    Set<Key<?>> keys();
+
+    /**
+     * Returns the value associated to the given key.
+     *
+     * @param <V> type of value to get
+     * @param key key of the value to get
+     * @return value associated to the given key, or {@code null} if none
+     */
+    <V> V get(@Nonnull Key<V> key);

Review Comment:
   `Optional<V>` as a return value ?



##########
api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java:
##########
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The option of a Java command-line tool where to place the paths to some 
dependencies.
+ * A {@code PathType} can identify the class-path, the module-path, the 
patches for a specific module,
+ * or another kind of path. This class is like an enumeration, except that it 
is extensible:
+ * plugins can define their own kinds of path.
+ *
+ * <p>One path type is handled in a special way: contrarily to other options,
+ * the paths specified in a {@code --patch-module} Java option is effective 
only for a specified module.
+ * This type is created by calls to {@link #patchModule(String)} and a new 
instance must be created for
+ * every module to patch.</p>
+ *
+ * <p>Path types are often exclusive. For example, a dependency should not be 
both on the Java class-path
+ * and on the Java module-path.</p>
+ *
+ * @see 
org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths()
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public final class JavaPathType extends PathType {
+    /**
+     * The path identified by the Java {@code --class-path} option.
+     * Used for compilation, execution and Javadoc among others.
+     *
+     * <h4>Context-sensitive interpretation</h4>
+     * A dependency with this path type will not necessarily be placed on the 
class-path.
+     * There is two circumstances where the dependency may be nevertheless 
placed somewhere else:
+     *
+     * <ul>
+     *   <li>If {@link #MODULES} path type is also set, then the dependency 
can be placed either on the
+     *       class-path or on the module-path, but only one of those. The 
choice is up to the plugin,
+     *       possibly using heuristic rules (Maven 3 behavior).</li>
+     *   <li>If a {@link #patchModule(String)} is also set and the main JAR 
file was placed on the module-path,
+     *       then the test dependency will be placed on the Java {@code 
--patch-module} option instead of the
+     *       class-path.</li>
+     * </ul>
+     */
+    public static final JavaPathType CLASSES = new JavaPathType("CLASSES", 
"--class-path", null);
+
+    /**
+     * The path identified by the Java {@code --module-path} option.
+     * Used for compilation, execution and Javadoc among others.
+     *
+     * <h4>Context-sensitive interpretation</h4>
+     * A dependency with this flag will not necessarily be placed on the 
module-path.
+     * There is two circumstances where the dependency may be nevertheless 
placed somewhere else:
+     *
+     * <ul>
+     *   <li>If {@link #CLASSES} path type is also set, then the dependency 
<em>should</em> be placed on the
+     *       module-path, but is nevertheless compatible with placement on the 
class-path. Compatibility can
+     *       be achieved, for example, by repeating in the {@code 
META-INF/services/} directory the services
+     *       that are declared in the {@code module-info.class} file. In that 
case, the path type can be chosen
+     *       by the plugin.</li>
+     *   <li>If a {@link #patchModule(String)} is also set and the main JAR 
file was placed on the module-path,
+     *       then the test dependency will be placed on the Java {@code 
--patch-module} option instead of the
+     *       module-path.</li>

Review Comment:
   `module-path` -> `{@code --module-path}` for consistency



##########
api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java:
##########
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.StringJoiner;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The option of a Java command-line tool where to place the paths to some 
dependencies.
+ * A {@code PathType} can identify the class-path, the module-path, the 
patches for a specific module,
+ * or another kind of path. This class is like an enumeration, except that it 
is extensible:
+ * plugins can define their own kinds of path.
+ *
+ * <p>One path type is handled in a special way: contrarily to other options,
+ * the paths specified in a {@code --patch-module} Java option is effective 
only for a specified module.
+ * This type is created by calls to {@link #patchModule(String)} and a new 
instance must be created for
+ * every module to patch.</p>
+ *
+ * <p>Path types are often exclusive. For example, a dependency should not be 
both on the Java class-path
+ * and on the Java module-path.</p>
+ *
+ * @see 
org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths()
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public final class JavaPathType extends PathType {
+    /**
+     * The path identified by the Java {@code --class-path} option.
+     * Used for compilation, execution and Javadoc among others.
+     *
+     * <h4>Context-sensitive interpretation</h4>
+     * A dependency with this path type will not necessarily be placed on the 
class-path.
+     * There is two circumstances where the dependency may be nevertheless 
placed somewhere else:
+     *
+     * <ul>
+     *   <li>If {@link #MODULES} path type is also set, then the dependency 
can be placed either on the
+     *       class-path or on the module-path, but only one of those. The 
choice is up to the plugin,
+     *       possibly using heuristic rules (Maven 3 behavior).</li>
+     *   <li>If a {@link #patchModule(String)} is also set and the main JAR 
file was placed on the module-path,
+     *       then the test dependency will be placed on the Java {@code 
--patch-module} option instead of the
+     *       class-path.</li>
+     * </ul>
+     */
+    public static final JavaPathType CLASSES = new JavaPathType("CLASSES", 
"--class-path", null);
+
+    /**
+     * The path identified by the Java {@code --module-path} option.
+     * Used for compilation, execution and Javadoc among others.
+     *
+     * <h4>Context-sensitive interpretation</h4>
+     * A dependency with this flag will not necessarily be placed on the 
module-path.
+     * There is two circumstances where the dependency may be nevertheless 
placed somewhere else:

Review Comment:
   `There is` -> `There are`
   `be nevertheless` -> `nevertheless be`





> Control the type of path where each dependency can be placed
> ------------------------------------------------------------
>
>                 Key: MNG-8015
>                 URL: https://issues.apache.org/jira/browse/MNG-8015
>             Project: Maven
>          Issue Type: Improvement
>          Components: Core
>    Affects Versions: 4.0.0-alpha-12
>            Reporter: Martin Desruisseaux
>            Priority: Major
>
> Make possible to declare where each dependency can be placed: on the 
> module-path, class-path, agent path, doclet path, taglet path, annotation 
> processing path, _etc._ The proposed improvement consists in adding a new 
> {{PATH_TYPES}} property that can be associated to dependencies. The property 
> value is an array of {{PathType}}, a new enumeration-like class with values 
> such as {{CLASSES}}, {{MODULES}}, {{DOCLET}}, _etc._ Contrarily to real Java 
> enumerations, this enumeration-like class is extensible: plugins can add 
> their own enumeration values. This is required at least for the 
> {{--patch-module}} option, where a new {{PathType}} enumeration value need to 
> be created for each module to patch.
> Users can control indirectly the {{PathType}} of a dependency by specifying 
> the dependency type. Note that there is no direct mapping between the 
> dependency type and where the dependency will be placed, but only an indirect 
> mapping caused by the fact that using a dependency type implies implicit 
> values of some properties such as classifier, and (with this proposal) path 
> types:
>  * {{<type>jar</type>}} implies {{PathType.CLASSES}} and {{PathType.MODULES}}.
>  * {{<type>modular-jar</type>}} implies {{PathType.MODULES}} only.
>  * {{<type>classpath-jar</type>}} implies {{PathType.CLASSES}} only.
>  * _etc._
> When a plugin requests the paths of dependencies, the plugin specifies the 
> types of path it is interested in. For example, a Java compiler plugin can 
> specify that it is interested in {{PathType.CLASSES}} and 
> {{PathType.MODULES}}, but not {{PathType.DOCLET}}. If a dependency declared 
> that it can be placed on the class-path or the doclet-path, only the 
> class-path is left after intersection with plugin's request. This is 
> important for the next step.
> If, after all filtering such as above paragraph are applied, a dependency has 
> only one {{PathType}} left, then there is no ambiguity and we are done. 
> Combined with above-cited dependency types like {{modular-jar}} or 
> {{classpath-jar}}, this rule allows users to control where the dependency 
> will be placed. But if there are two or more {{PathType}} left after 
> filtering, then a choice needs to be done. For example if there are both 
> {{PathType.CLASSES}} and {{PathType.MODULES}} (which may happen when 
> {{<type>jar</type>}} is used), then an heuristic rule similar to Maven 3 can 
> be applied: check if a {{module-info.class}} file or an {{Automatic-Name}} 
> manifest attribute is present, and base the decision on that.
> This proposal aims to fix MNG-7855.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to