[
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)