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

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

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


##########
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:
   I think it would not avoid the "unchecked cast" compiler warning. An easier 
approach would be to replace this property by an ordinary `Set<PathType> 
getPathTypes()` method in the `Dependency` interface.





> 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