[ https://issues.apache.org/jira/browse/MNG-8015?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17808674#comment-17808674 ]
ASF GitHub Bot commented on MNG-8015: ------------------------------------- gnodet commented on code in PR #1378: URL: https://github.com/apache/maven/pull/1378#discussion_r1459072073 ########## 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: Would it make sense to remove the `intern()` method and redefine `forName` as: ``` @Nullable public static <T> Key<T> forName(@Nonnull String name, @Nullable Class<T> defaultType, boolean intern) { Key<?> key; synchronized (INTERNS) { key = INTERNS.get(name); if (defaultType != null) { if (key == null) { key = new Key<>(name, defaultType); if (intern) { INTERNS.put(name, key); } } else if (key.valueType() != defaultType && intern) { throw new IllegalStateException("Key " + name + " already exists for a different class of values."); } } } return (Key) key; } ``` The constructor could be made `private`, so that the only entry point is the above method. > 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)