From c0a838decf90dddba49b57ef9678ff78ca945156 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sun, 7 Jan 2024 14:57:09 +0100 Subject: [PATCH 01/31] [MNG-8015] Control the type of path where each dependency can be placed - Refactor some `MavenProject` methods for reducing code duplication. Their behavior should be as before. - Add `@Override` annotations. --- .../java/org/apache/maven/api/Dependency.java | 1 + .../maven/artifact/DefaultArtifact.java | 47 ++++++ .../artifact/handler/ArtifactHandlerMock.java | 7 + .../maven/repository/TestArtifactHandler.java | 7 + .../DefaultArtifactHandlerManager.java | 2 + .../impl/TransformedArtifactHandler.java | 7 + .../apache/maven/project/MavenProject.java | 137 ++++++++++-------- .../project/artifact/PluginArtifact.java | 7 + .../project/artifact/ProjectArtifact.java | 7 + .../internal/impl/TestArtifactHandler.java | 7 + 10 files changed, 165 insertions(+), 64 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java index efad1415adf8..be64e0f859ee 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java @@ -49,5 +49,6 @@ public interface Dependency extends Artifact { * @return a {@link DependencyCoordinate} */ @Nonnull + @Override DependencyCoordinate toCoordinate(); } diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java index 9a1ca1f4336b..44f2615790ca 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java @@ -181,52 +181,64 @@ private boolean empty(String value) { return (value == null) || (value.trim().length() < 1); } + @Override public String getClassifier() { return classifier; } + @Override public boolean hasClassifier() { return classifier != null && !classifier.isEmpty(); } + @Override public String getScope() { return scope; } + @Override public String getGroupId() { return groupId; } + @Override public String getArtifactId() { return artifactId; } + @Override public String getVersion() { return version; } + @Override public void setVersion(String version) { this.version = version; setBaseVersionInternal(version); versionRange = null; } + @Override public String getType() { return type; } + @Override public void setFile(File file) { this.file = file; } + @Override public File getFile() { return file; } + @Override public ArtifactRepository getRepository() { return repository; } + @Override public void setRepository(ArtifactRepository repository) { this.repository = repository; } @@ -235,10 +247,12 @@ public void setRepository(ArtifactRepository repository) { // // ---------------------------------------------------------------------- + @Override public String getId() { return getDependencyConflictId() + ":" + getBaseVersion(); } + @Override public String getDependencyConflictId() { StringBuilder sb = new StringBuilder(128); sb.append(getGroupId()); @@ -257,6 +271,7 @@ private void appendArtifactTypeClassifierString(StringBuilder sb) { } } + @Override public void addMetadata(ArtifactMetadata metadata) { if (metadataMap == null) { metadataMap = new HashMap<>(); @@ -270,6 +285,7 @@ public void addMetadata(ArtifactMetadata metadata) { } } + @Override public Collection getMetadataList() { if (metadataMap == null) { return Collections.emptyList(); @@ -282,6 +298,7 @@ public Collection getMetadataList() { // Object overrides // ---------------------------------------------------------------------- + @Override public String toString() { StringBuilder sb = new StringBuilder(); if (getGroupId() != null) { @@ -323,6 +340,7 @@ public int hashCode() { return Objects.hash(groupId, artifactId, type, classifier, version); } + @Override public String getBaseVersion() { if (baseVersion == null && version != null) { setBaseVersionInternal(version); @@ -339,6 +357,7 @@ protected String getBaseVersionInternal() { return baseVersion; } + @Override public void setBaseVersion(String baseVersion) { setBaseVersionInternal(baseVersion); } @@ -347,6 +366,7 @@ protected void setBaseVersionInternal(String baseVersion) { this.baseVersion = ArtifactUtils.toSnapshotVersion(baseVersion); } + @Override public int compareTo(Artifact a) { int result = groupId.compareTo(a.getGroupId()); if (result == 0) { @@ -376,47 +396,58 @@ public int compareTo(Artifact a) { return result; } + @Override public void updateVersion(String version, ArtifactRepository localRepository) { setResolvedVersion(version); setFile(new File(localRepository.getBasedir(), localRepository.pathOf(this))); } + @Override public String getDownloadUrl() { return downloadUrl; } + @Override public void setDownloadUrl(String downloadUrl) { this.downloadUrl = downloadUrl; } + @Override public ArtifactFilter getDependencyFilter() { return dependencyFilter; } + @Override public void setDependencyFilter(ArtifactFilter artifactFilter) { dependencyFilter = artifactFilter; } + @Override public ArtifactHandler getArtifactHandler() { return artifactHandler; } + @Override public List getDependencyTrail() { return dependencyTrail; } + @Override public void setDependencyTrail(List dependencyTrail) { this.dependencyTrail = dependencyTrail; } + @Override public void setScope(String scope) { this.scope = scope; } + @Override public VersionRange getVersionRange() { return versionRange; } + @Override public void setVersionRange(VersionRange versionRange) { this.versionRange = versionRange; selectVersionFromNewRangeIfAvailable(); @@ -431,70 +462,86 @@ private void selectVersionFromNewRangeIfAvailable() { } } + @Override public void selectVersion(String version) { this.version = version; setBaseVersionInternal(version); } + @Override public void setGroupId(String groupId) { this.groupId = groupId; } + @Override public void setArtifactId(String artifactId) { this.artifactId = artifactId; } + @Override public boolean isSnapshot() { return getBaseVersion() != null && (getBaseVersion().endsWith(SNAPSHOT_VERSION) || getBaseVersion().equals(LATEST_VERSION)); } + @Override public void setResolved(boolean resolved) { this.resolved = resolved; } + @Override public boolean isResolved() { return resolved; } + @Override public void setResolvedVersion(String version) { this.version = version; // retain baseVersion } + @Override public void setArtifactHandler(ArtifactHandler artifactHandler) { this.artifactHandler = artifactHandler; } + @Override public void setRelease(boolean release) { this.release = release; } + @Override public boolean isRelease() { return release; } + @Override public List getAvailableVersions() { return availableVersions; } + @Override public void setAvailableVersions(List availableVersions) { this.availableVersions = availableVersions; } + @Override public boolean isOptional() { return optional; } + @Override public ArtifactVersion getSelectedVersion() throws OverConstrainedVersionException { return versionRange.getSelectedVersion(this); } + @Override public boolean isSelectedVersionKnown() throws OverConstrainedVersionException { return versionRange.isSelectedVersionKnown(this); } + @Override public void setOptional(boolean optional) { this.optional = optional; } diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java b/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java index deb3e77c5456..8f8dd820e0cf 100644 --- a/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java +++ b/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java @@ -27,6 +27,7 @@ public void setExtension(String extension) { this.extension = extension; } + @Override public String getExtension() { return extension; } @@ -35,6 +36,7 @@ public void setDirectory(String directory) { this.directory = directory; } + @Override public String getDirectory() { return directory; } @@ -43,6 +45,7 @@ public void setClassifier(String classifier) { this.classifier = classifier; } + @Override public String getClassifier() { return classifier; } @@ -51,6 +54,7 @@ public void setPackaging(String packaging) { this.packaging = packaging; } + @Override public String getPackaging() { return packaging; } @@ -59,6 +63,7 @@ public void setIncludesDependencies(boolean includesDependencies) { this.includesDependencies = includesDependencies; } + @Override public boolean isIncludesDependencies() { return includesDependencies; } @@ -67,6 +72,7 @@ public void setLanguage(String language) { this.language = language; } + @Override public String getLanguage() { return language; } @@ -75,6 +81,7 @@ public void setAddedToClasspath(boolean addedToClasspath) { this.addedToClasspath = addedToClasspath; } + @Override public boolean isAddedToClasspath() { return addedToClasspath; } diff --git a/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java b/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java index 860fbe3fb528..5e02488d0716 100644 --- a/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java +++ b/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java @@ -39,30 +39,37 @@ public TestArtifactHandler(String type, String extension) { this.extension = extension; } + @Override public String getClassifier() { return null; } + @Override public String getDirectory() { return getPackaging() + "s"; } + @Override public String getExtension() { return extension; } + @Override public String getLanguage() { return "java"; } + @Override public String getPackaging() { return type; } + @Override public boolean isAddedToClasspath() { return true; } + @Override public boolean isIncludesDependencies() { return false; } diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java index 87166eb29a75..f873d817089c 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java @@ -60,6 +60,7 @@ public void onEvent(Object event) { } } + @Override public ArtifactHandler getArtifactHandler(String id) { return allHandlers.computeIfAbsent(id, k -> { Type type = typeRegistry.getType(id); @@ -75,6 +76,7 @@ public ArtifactHandler getArtifactHandler(String id) { }); } + @Override public void addHandlers(Map handlers) { throw new UnsupportedOperationException("Adding handlers programmatically is not supported anymore"); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java index 80ba4e7cdf2e..b2a1f9c2742b 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java @@ -36,30 +36,37 @@ class TransformedArtifactHandler implements ArtifactHandler { this.packaging = requireNonNull(packaging); } + @Override public String getClassifier() { return classifier; } + @Override public String getDirectory() { return null; } + @Override public String getExtension() { return extension; } + @Override public String getLanguage() { return "none"; } + @Override public String getPackaging() { return packaging; } + @Override public boolean isAddedToClasspath() { return false; } + @Override public boolean isIncludesDependencies() { return false; } diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java index 0e165e04cb30..854344497493 100644 --- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java +++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java @@ -32,12 +32,14 @@ import java.util.Objects; import java.util.Properties; import java.util.Set; +import java.util.function.Predicate; import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.artifact.DependencyResolutionRequiredException; import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.filter.ArtifactFilter; import org.apache.maven.lifecycle.internal.DefaultProjectArtifactFactory; @@ -320,68 +322,85 @@ public List getTestCompileSourceRoots() { return testCompileSourceRoots; } - public List getCompileClasspathElements() throws DependencyResolutionRequiredException { - List list = new ArrayList<>(getArtifacts().size() + 1); - - String d = getBuild().getOutputDirectory(); - if (d != null) { - list.add(d); - } - - for (Artifact a : getArtifacts()) { - if (a.getArtifactHandler().isAddedToClasspath()) { - // TODO let the scope handler deal with this - if (Artifact.SCOPE_COMPILE.equals(a.getScope()) - || Artifact.SCOPE_PROVIDED.equals(a.getScope()) - || Artifact.SCOPE_SYSTEM.equals(a.getScope())) { - addArtifactPath(a, list); - } - } - } + // TODO let the scope handler deal with this + private static boolean isCompilePathElement(final String scope) { + return Artifact.SCOPE_COMPILE.equals(scope) + || Artifact.SCOPE_PROVIDED.equals(scope) + || Artifact.SCOPE_SYSTEM.equals(scope); + } - return list; + // TODO let the scope handler deal with this + private static boolean isRuntimePathElement(final String scope) { + return Artifact.SCOPE_COMPILE.equals(scope) || Artifact.SCOPE_RUNTIME.equals(scope); } - // TODO this checking for file == null happens because the resolver has been confused about the root - // artifact or not. things like the stupid dummy artifact coming from surefire. - public List getTestClasspathElements() throws DependencyResolutionRequiredException { - List list = new ArrayList<>(getArtifacts().size() + 2); + // TODO let the scope handler deal with this + private static boolean isTestPathElement(final String scope) { + return true; + } - String d = getBuild().getTestOutputDirectory(); - if (d != null) { - list.add(d); + /** + * Returns a filtered list of classpath elements. This method is invoked when the caller + * requested that all dependencies are placed on the classpath, with no module-path element. + * + * @param scopeFilter a filter returning {@code true} for the artifact scopes to accept. + * @param includeTestDir whether to include the test directory in the classpath elements. + * @return paths of all artifacts placed on the classpath. + * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + */ + private List getClasspathElements(final Predicate scopeFilter, final boolean includeTestDir) + throws DependencyResolutionRequiredException { + final List list = new ArrayList<>(getArtifacts().size() + 2); + if (includeTestDir) { + String d = getBuild().getTestOutputDirectory(); + if (d != null) { + list.add(d); + } } - - d = getBuild().getOutputDirectory(); + String d = getBuild().getOutputDirectory(); if (d != null) { list.add(d); } - for (Artifact a : getArtifacts()) { - if (a.getArtifactHandler().isAddedToClasspath()) { - addArtifactPath(a, list); + final File f = a.getFile(); + if (f != null && scopeFilter.test(a.getScope())) { + final ArtifactHandler h = a.getArtifactHandler(); + if (h.isAddedToClasspath()) { + list.add(f.getPath()); + } } } - return list; } - public List getRuntimeClasspathElements() throws DependencyResolutionRequiredException { - List list = new ArrayList<>(getArtifacts().size() + 1); + /** + * Returns the elements placed on the classpath for compilation. + * This method can be invoked when the caller does not support module-path. + * + * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + */ + public List getCompileClasspathElements() throws DependencyResolutionRequiredException { + return getClasspathElements(MavenProject::isCompilePathElement, false); + } - String d = getBuild().getOutputDirectory(); - if (d != null) { - list.add(d); - } + /** + * Returns the elements placed on the classpath for tests. + * This method can be invoked when the caller does not support module-path. + * + * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + */ + public List getTestClasspathElements() throws DependencyResolutionRequiredException { + return getClasspathElements(MavenProject::isTestPathElement, true); + } - for (Artifact a : getArtifacts()) { - if (a.getArtifactHandler().isAddedToClasspath() - // TODO let the scope handler deal with this - && (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope()))) { - addArtifactPath(a, list); - } - } - return list; + /** + * Returns the elements placed on the classpath for runtime. + * This method can be invoked when the caller does not support module-path. + * + * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + */ + public List getRuntimeClasspathElements() throws DependencyResolutionRequiredException { + return getClasspathElements(MavenProject::isRuntimePathElement, false); } // ---------------------------------------------------------------------- @@ -1111,13 +1130,6 @@ private void deepCopy(MavenProject project) { lifecyclePhases.addAll(project.lifecyclePhases); } - private void addArtifactPath(Artifact artifact, List classpath) { - File file = artifact.getFile(); - if (file != null) { - classpath.add(file.getPath()); - } - } - private static String getProjectReferenceId(String groupId, String artifactId, String version) { StringBuilder buffer = new StringBuilder(128); buffer.append(groupId).append(':').append(artifactId).append(':').append(version); @@ -1347,9 +1359,7 @@ public List getCompileArtifacts() { // TODO classpath check doesn't belong here - that's the other method if (a.getArtifactHandler().isAddedToClasspath()) { // TODO let the scope handler deal with this - if (Artifact.SCOPE_COMPILE.equals(a.getScope()) - || Artifact.SCOPE_PROVIDED.equals(a.getScope()) - || Artifact.SCOPE_SYSTEM.equals(a.getScope())) { + if (isCompilePathElement(a.getScope())) { list.add(a); } } @@ -1369,9 +1379,7 @@ public List getCompileDependencies() { for (Artifact a : getArtifacts()) { // TODO let the scope handler deal with this - if (Artifact.SCOPE_COMPILE.equals(a.getScope()) - || Artifact.SCOPE_PROVIDED.equals(a.getScope()) - || Artifact.SCOPE_SYSTEM.equals(a.getScope())) { + if (isCompilePathElement(a.getScope())) { Dependency dependency = new Dependency(); dependency.setArtifactId(a.getArtifactId()); @@ -1437,7 +1445,7 @@ public List getRuntimeDependencies() { for (Artifact a : getArtifacts()) { // TODO let the scope handler deal with this - if (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope())) { + if (isRuntimePathElement(a.getScope())) { Dependency dependency = new Dependency(); dependency.setArtifactId(a.getArtifactId()); @@ -1459,9 +1467,7 @@ public List getRuntimeArtifacts() { for (Artifact a : getArtifacts()) { // TODO classpath check doesn't belong here - that's the other method - if (a.getArtifactHandler().isAddedToClasspath() - // TODO let the scope handler deal with this - && (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope()))) { + if (a.getArtifactHandler().isAddedToClasspath() && isRuntimePathElement(a.getScope())) { list.add(a); } } @@ -1481,7 +1487,10 @@ public List getSystemClasspathElements() throws DependencyResolutionRequ if (a.getArtifactHandler().isAddedToClasspath()) { // TODO let the scope handler deal with this if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) { - addArtifactPath(a, list); + File f = a.getFile(); + if (f != null) { + list.add(f.getPath()); + } } } } diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java index d5bb916664dc..bf266e717fc0 100644 --- a/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java +++ b/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java @@ -57,30 +57,37 @@ public List getManagedDependencies() { // TODO: this is duplicate of MavenPluginArtifactHandlerProvider provided one static class PluginArtifactHandler implements ArtifactHandler { + @Override public String getClassifier() { return null; } + @Override public String getDirectory() { return null; } + @Override public String getExtension() { return "jar"; } + @Override public String getLanguage() { return "none"; } + @Override public String getPackaging() { return "maven-plugin"; } + @Override public boolean isAddedToClasspath() { return true; } + @Override public boolean isIncludesDependencies() { return false; } diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java index 8d75eb76c576..965b37097017 100644 --- a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java +++ b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java @@ -62,30 +62,37 @@ public List getManagedDependencies() { // TODO: this is duplicate of PomArtifactHandlerProvider provided one static class PomArtifactHandler implements ArtifactHandler { + @Override public String getClassifier() { return null; } + @Override public String getDirectory() { return null; } + @Override public String getExtension() { return "pom"; } + @Override public String getLanguage() { return "none"; } + @Override public String getPackaging() { return "pom"; } + @Override public boolean isAddedToClasspath() { return false; } + @Override public boolean isIncludesDependencies() { return false; } diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java index cb86c6efdbc7..68281e9169c9 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java +++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java @@ -39,30 +39,37 @@ public TestArtifactHandler(String type, String extension) { this.extension = extension; } + @Override public String getClassifier() { return null; } + @Override public String getDirectory() { return getPackaging() + "s"; } + @Override public String getExtension() { return extension; } + @Override public String getLanguage() { return "java"; } + @Override public String getPackaging() { return type; } + @Override public boolean isAddedToClasspath() { return true; } + @Override public boolean isIncludesDependencies() { return false; } From c8b754c03b2a6824d2421028f32ae078b5f5deb8 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Mon, 8 Jan 2024 00:05:24 +0100 Subject: [PATCH 02/31] [MNG-8015] Control the type of path where each dependency can be placed Refactor `DependencyProperties` as a type-safe map of objects instead of a map of strings. This is in anticipation for the introduction of a `PathType` property in future commits. The type of property values is specified by `DependencyProperties.Key.valueType()`. --- .../maven/api/DependencyProperties.java | 205 +++++++++++++++++- .../internal/impl/DefaultDependency.java | 26 ++- .../impl/DefaultDependencyProperties.java | 190 ++++++++++++++-- .../maven/internal/impl/DefaultType.java | 15 +- .../internal/impl/DefaultTypeRegistry.java | 13 +- 5 files changed, 402 insertions(+), 47 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java index 9f634168480b..16f25334094d 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java @@ -18,7 +18,10 @@ */ package org.apache.maven.api; +import java.util.HashMap; import java.util.Map; +import java.util.Objects; +import java.util.Set; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; @@ -33,27 +36,209 @@ @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 type of value associated to the key + */ + class Key { + /** + * 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> INTERNS = new HashMap<>(); + + /** + * Value returned by {@link #name()}. + */ + @Nonnull + private final String name; + + /** + * Value returned by {@link #valueType()}. + */ + @Nonnull + private final Class 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 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 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 intern() { + Key previous; + synchronized (INTERNS) { + previous = INTERNS.putIfAbsent(name, this); + } + if (previous == null) { + return this; + } + if (equals(previous)) { + return (Key) 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 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 LANGUAGE = new Key<>("language", String.class).intern(); + + /** + * Boolean flag telling that dependency contains all of its dependencies. *

* Important: this flag must be kept in sync with resolver! (as is used during collection) */ - String FLAG_INCLUDES_DEPENDENCIES = "includesDependencies"; + Key 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. */ - String FLAG_CLASS_PATH_CONSTITUENT = "classPathConstituent"; + Key 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 asMap(); + Set> keys(); + + /** + * Returns the value associated to the given key. + * + * @param 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 get(@Nonnull Key key); + + /** + * Returns the value associated to the given key, or the given default value if none. + * + * @param 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 getOrDefault(@Nonnull Key key, V defaultValue); /** * Returns {@code true} if given flag is {@code true}. + * An absence of value is interpreted as {@code false}. + * + * @param flag the property to check + * @return whether the value associated to the given key is non-null and true + */ + default boolean checkFlag(@Nonnull Key flag) { + return Boolean.TRUE.equals(get(flag)); + } + + /** + * {@return an immutable "map view" of all the properties}. + * This method is provided for compatibility with API working with {@link String}. + * The type-safe method expecting {@link Key} arguments should be preferred. */ - boolean checkFlag(@Nonnull String flag); + @Nonnull + Map asMap(); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java index 3f2f06893ebf..45325d881545 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java @@ -18,7 +18,10 @@ */ package org.apache.maven.internal.impl; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; +import java.util.function.Function; import org.apache.maven.api.Artifact; import org.apache.maven.api.Dependency; @@ -36,6 +39,17 @@ import static org.apache.maven.internal.impl.Utils.nonNull; public class DefaultDependency implements Dependency { + /** + * A mapping from {@link ArtifactProperties} values to {@link DependencyProperties} values. + * Used for conversion from Eclipse model to Maven model of dependency properties. + */ + private static final Map, Function> VALUE_CONVERTERS = new HashMap<>(4); + + static { + VALUE_CONVERTERS.put(String.class, String::valueOf); + VALUE_CONVERTERS.put(Boolean.class, Boolean::valueOf); + } + private final InternalSession session; private final org.eclipse.aether.graph.Dependency dependency; private final DependencyProperties dependencyProperties; @@ -45,8 +59,16 @@ public DefaultDependency( @Nonnull InternalSession session, @Nonnull org.eclipse.aether.graph.Dependency dependency) { this.session = nonNull(session, "session"); this.dependency = nonNull(dependency, "dependency"); - this.dependencyProperties = - new DefaultDependencyProperties(dependency.getArtifact().getProperties()); + DefaultDependencyProperties.Builder builder = new DefaultDependencyProperties.Builder(); + for (Map.Entry entry : + dependency.getArtifact().getProperties().entrySet()) { + DependencyProperties.Key key = DependencyProperties.Key.forName(entry.getKey(), String.class); + Function vc = VALUE_CONVERTERS.get(key.valueType()); + if (vc != null) { + builder.checkAndSet(key, vc.apply(entry.getValue())); + } + } + this.dependencyProperties = builder.build(); this.key = getGroupId() + ':' + getArtifactId() diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java index 2ee780713034..a3147b889e6e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java @@ -18,11 +18,10 @@ */ package org.apache.maven.internal.impl; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.annotations.Nonnull; @@ -33,34 +32,189 @@ * Default implementation of artifact properties. */ public class DefaultDependencyProperties implements DependencyProperties { - private final Map properties; + /** + * The property values. The type of values is determined by the key. + */ + @Nonnull + private final Map, Object> properties; + + /** + * A builder of dependency properties. + * Each builder can be used only once. + */ + public static class Builder { + /** + * The property values to be assigned to {@link DefaultDependencyProperties} on completion. + * This is set to {@code null} after the dependency properties have been built, for preventing changes. + */ + private Map, Object> properties; + + /** + * Creates an initially empty builder. + */ + public Builder() { + properties = new HashMap<>(); + } + + /** + * Associates the given value to the given key. + * If a value was already defined for the given key, the new value replaces it. + * + *

Implementation note

+ * All setter methods in {@code Builder} ultimately delegate to this method. + * This architecture provides a single point that subclasses can override. + * + * @param type of value to add + * @param key key of the value to add + * @param value the value to add + * @return {@code this} for method call chaining + * @throws IllegalStateException if the dependency properties have already been built + */ + @Nonnull + public Builder set(@Nonnull Key key, @Nonnull V value) { + if (properties == null) { + throw new IllegalStateException("Already built."); + } + properties.put(nonNull(key, "key"), nonNull(value, "value")); + return this; + } + + /** + * Checks the type of the given value, then associates to the given key. + * + * @param type of value to add + * @param key key of the value to add + * @param value the value to add + * @return {@code this} for method call chaining + * @throws ClassCastException if the given value is not of type {@code } + * @throws IllegalStateException if the dependency properties have already been built + */ + public Builder checkAndSet(@Nonnull Key key, @Nonnull Object value) { + return set(key, key.valueType().cast(value)); + } + + /** + * Associates the value {@code Boolean.TRUE} to the given key. + * + * @param key key of the flag to set + * @return {@code this} for method call chaining + * @throws IllegalStateException if the dependency properties have already been built + */ + @Nonnull + public Builder setFlag(@Nonnull Key key) { + return set(key, Boolean.TRUE); + } + + /** + * Copies all values from the given dependency properties. + * + * @param source the dependency properties to copy + * @return {@code this} for method call chaining + * @throws IllegalStateException if the dependency properties have already been built + */ + public Builder setAll(@Nonnull DependencyProperties source) { + source.keys().forEach((key) -> checkAndSet(key, source.get(key))); + return this; + } - public DefaultDependencyProperties(String... flags) { - this(Arrays.asList(flags)); + /** + * {@return the dependency properties with the values previously set}. + * This method can be invoked only once. + */ + @Nonnull + public DefaultDependencyProperties build() { + Map, Object> map = properties; + if (map != null) { + properties = null; + return new DefaultDependencyProperties(map); + } + throw new IllegalStateException("Already built."); + } + } + + /** + * Creates dependency properties with the given map. The caller is responsible to ensure + * that all keys are associated to a value of the type specified by {@link Key#valueType()}. + * For safe construction, use the {@link Builder} instead. + * + * @param properties the map which will be backing the dependency properties + */ + protected DefaultDependencyProperties(@Nonnull final Map, Object> properties) { + this.properties = nonNull(properties, "properties"); } - public DefaultDependencyProperties(@Nonnull Collection flags) { - nonNull(flags, "flags"); - HashMap map = new HashMap<>(); - for (String flag : flags) { - map.put(flag, Boolean.TRUE.toString()); + /** + * Creates new dependency properties with the given flag sets to {@code true}. + * + * @param flags the flags to set to {@code true} + */ + @SafeVarargs + public DefaultDependencyProperties(@Nonnull Key... flags) { + int count = nonNull(flags, "flags").length; + properties = new HashMap<>(count + count / 3); + for (Key flag : flags) { + properties.put(flag, Boolean.TRUE); } - this.properties = Collections.unmodifiableMap(map); } - public DefaultDependencyProperties(@Nonnull Map properties) { - this.properties = Collections.unmodifiableMap(nonNull(properties, "properties")); + /** + * {@return the keys of all properties in this map}. + */ + @Override + public Set> keys() { + return Collections.unmodifiableSet(properties.keySet()); + } + + /** + * Returns the value associated to the given key. + * + * @param 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 + */ + @Override + public V get(Key key) { + return key.valueType().cast(properties.get(key)); + } + + /** + * Returns the value associated to the given key, or the given default value if none. + * + * @param 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 + */ + @Override + public V getOrDefault(Key key, V defaultValue) { + return key.valueType().cast(properties.getOrDefault(key, defaultValue)); } + private transient Map mapView; + + /** + * {@return an immutable "map view" of all the properties}. + * This is computed when first needed + */ @Nonnull @Override - public Map asMap() { - return properties; + public synchronized Map asMap() { + if (mapView == null) { + int count = properties.size(); + Map m = new HashMap<>(count + count / 3); + for (Map.Entry, Object> entry : properties.entrySet()) { + m.put(entry.getKey().name(), entry.getValue().toString()); + } + mapView = Collections.unmodifiableMap(m); + } + return mapView; } + /** + * {@return a string representation of the key-value mapping}. + */ @Override - public boolean checkFlag(@Nonnull String flag) { - nonNull(flag, "flag"); - return Boolean.parseBoolean(properties.getOrDefault(flag, "")); + public String toString() { + return properties.toString(); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java index 6297f5c4dde0..91ad258d6371 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java @@ -18,12 +18,10 @@ */ package org.apache.maven.internal.impl; -import java.util.HashMap; import java.util.Map; import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Type; -import org.eclipse.aether.artifact.ArtifactProperties; import org.eclipse.aether.artifact.ArtifactType; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -46,20 +44,21 @@ public DefaultType( this.extension = nonNull(extension, "extension"); this.classifier = classifier; nonNull(dependencyProperties, "dependencyProperties"); - HashMap props = new HashMap<>(dependencyProperties.asMap()); - props.put(ArtifactProperties.TYPE, id); - props.put(ArtifactProperties.LANGUAGE, language); - this.dependencyProperties = new DefaultDependencyProperties(props); + DefaultDependencyProperties.Builder props = new DefaultDependencyProperties.Builder() + .setAll(dependencyProperties) + .set(DependencyProperties.TYPE, id) + .set(DependencyProperties.LANGUAGE, language); + this.dependencyProperties = props.build(); } @Override public String getId() { - return dependencyProperties.asMap().get(ArtifactProperties.TYPE); + return dependencyProperties.get(DependencyProperties.TYPE); } @Override public String getLanguage() { - return dependencyProperties.asMap().get(ArtifactProperties.LANGUAGE); + return dependencyProperties.get(DependencyProperties.LANGUAGE); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java index cebd30cc666a..a7ebb5126275 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java @@ -22,7 +22,6 @@ import javax.inject.Named; import javax.inject.Singleton; -import java.util.ArrayList; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -78,19 +77,15 @@ public Type getType(String id) { type = legacyTypes.computeIfAbsent(id, k -> { // Copy data as the ArtifactHandler is not immutable, but Type should be. ArtifactHandler handler = manager.getArtifactHandler(id); - ArrayList flags = new ArrayList<>(); + DefaultDependencyProperties.Builder flags = new DefaultDependencyProperties.Builder(); if (handler.isAddedToClasspath()) { - flags.add(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT); + flags.setFlag(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT); } if (handler.isIncludesDependencies()) { - flags.add(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); + flags.setFlag(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); } return new DefaultType( - id, - handler.getLanguage(), - handler.getExtension(), - handler.getClassifier(), - new DefaultDependencyProperties(flags)); + id, handler.getLanguage(), handler.getExtension(), handler.getClassifier(), flags.build()); }); } return type; From 74baea1bca3b3b45ed5203b7a84be8df4e011b47 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sun, 7 Jan 2024 17:10:06 +0100 Subject: [PATCH 03/31] [MNG-8015] Control the type of path where each dependency can be placed - Add a `PathType` enumeration (actually a class for making the enumeration extensible). - Add a `DependencyResolverResult.getDispatchedPath()` method, unimplemented for now. - Move `DefaultDependencyResolverResult` as a top-level class for further developments. - Some changes in `DefaultDependencyResolver` in anticipation for further developments. --- .../org/apache/maven/api/JavaPathType.java | 240 ++++++++++++++++++ .../java/org/apache/maven/api/PathType.java | 142 +++++++++++ .../services/DependencyResolverResult.java | 46 ++++ .../impl/DefaultDependencyResolver.java | 87 ++----- .../impl/DefaultDependencyResolverResult.java | 108 ++++++++ 5 files changed, 560 insertions(+), 63 deletions(-) create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java new file mode 100644 index 000000000000..e936a8158eb5 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java @@ -0,0 +1,240 @@ +/* + * 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. + * + *

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.

+ * + *

Path types are often exclusive. For example, a dependency should not be both on the Java class-path + * and on the Java module-path.

+ * + * @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. + */ + 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. + */ + public static final JavaPathType MODULES = new JavaPathType("MODULES", "--module-path", null); + + /** + * The path identified by the Java {@code --upgrade-module-path} option. + */ + public static final JavaPathType UPGRADE_MODULES = + new JavaPathType("UPGRADE_MODULES", "--upgrade-module-path", null); + + /** + * The path identified by the Java {@code --processor-path} option. + */ + public static final JavaPathType PROCESSOR_CLASSES = + new JavaPathType("PROCESSOR_CLASSES", "--processor-path", null); + + /** + * The path identified by the Java {@code --processor-module-path} option. + */ + public static final JavaPathType PROCESSOR_MODULES = + new JavaPathType("PROCESSOR_MODULES", "--processor-module-path", null); + + /** + * The path identified by the Java {@code -agentpath} option. + */ + public static final JavaPathType AGENT = new JavaPathType("AGENT", "-agentpath", null); + + /** + * The path identified by the Javadoc {@code -doclet} option. + */ + public static final JavaPathType DOCLET = new JavaPathType("DOCLET", "-doclet", null); + + /** + * The path identified by the Javadoc {@code -tagletpath} option. + */ + public static final JavaPathType TAGLETS = new JavaPathType("TAGLETS", "-tagletpath", null); + + /** + * All predefined enumeration values. + */ + private static final JavaPathType[] VALUES = { + CLASSES, MODULES, UPGRADE_MODULES, PROCESSOR_CLASSES, PROCESSOR_MODULES, AGENT, DOCLET, TAGLETS + }; + + /** + * Creates a path identified by the Java {@code --patch-module} option. + * Contrarily to the other types of paths, this path is applied to only + * one specific module. Used for compilation and execution among others. + * + * @param moduleName name of the module on which to apply the path + * @return an identification of the patch-module path for the given module. + * + * @see #moduleName() + * @see #toString() + */ + @Nonnull + public static JavaPathType patchModule(final String moduleName) { + return new JavaPathType("patchModule", "--patch-module", Objects.requireNonNull(moduleName)); + } + + /** + * Creates a path for the specified option. If the {@code option} argument is one of the options + * associated to above-listed enumeration values, then that value is returned. Otherwise, this + * method returns a new {@code JavaPathType} instance for the given option. + * + * @param name the programmatic name of the new path type + * @param option the option associated to the path type, or {@code null} if none + * @return path type for the given option + */ + @Nonnull + public static JavaPathType forOption(final String name, final String option) { + for (final JavaPathType value : VALUES) { + if (value.option.equals(option)) { + return value; + } + } + return new JavaPathType(name, option, null); + } + + /** + * Name of the module to patch, or {@code null} if this path type is not for the {@code --patch-module} option. + */ + private final String moduleName; + + /** + * Creates a new enumeration value for a path associated to the given tool option. + * + * @param name the programmatic name of this path type + * @param option the Java tools option for this path, or {@code null} if none + * @param moduleName name of the module to patch, or {@code null} if none + */ + private JavaPathType(final String name, final String option, final String moduleName) { + super(name, option); + this.moduleName = moduleName; + } + + /** + * Returns the name of the module on which this option applies. + * This is present only for instances created by {@link #patchModule(String)}. + * + * @return name of the module on which this option applies + */ + @Nonnull + public Optional moduleName() { + return Optional.ofNullable(moduleName); + } + + /** + * Returns the programmatic name of this path type, including the class name and module to patch if any. + * For example, if this type is {@link #MODULES}, then this method returns {@code JavaPathType.MODULES}. + * If this type was created by {@code patchModule("foo.bar")}, then this method returns + * {@code JavaPathType.patchModule("foo.bar")}. + * + * @return the programmatic name together with the module name on which it applies + * + * @see #name() + * @see #moduleName() + */ + @Nonnull + @Override + public String toString() { + String s = super.toString(); + if (moduleName != null) { + s = s + "(\"" + moduleName + "\")"; + } + return s; + } + + /** + * Returns the option followed by a string representation of the given path elements. For example, + * if this type is {@link #MODULES}, then the option is {@code "--module-path"}. But if this type is + * {@code patchModule("foo.bar")}, then the option is {@code "--patch-module foo.bar"}. The option is followed + * by the given path elements, separated by the {@linkplain File#separatorChar platform-specific separator}. + * If the given {@code paths} argument contains no element, then this method returns an empty string. + * + * @param paths the path to format as a tool option + * @return the option associated to this path type followed by the given path elements, + * or an empty string if there is no path element + * @throws IllegalStateException if no option is associated to this path type + */ + @Nonnull + @Override + public String option(final Iterable paths) { + if (option == null) { + throw new IllegalStateException("No option is associated to this path type."); + } + String prefix = (moduleName == null) ? (option + ' ') : (option + ' ' + moduleName + '='); + StringJoiner joiner = new StringJoiner(File.pathSeparator, prefix, ""); + joiner.setEmptyValue(""); + for (Path p : paths) { + joiner.add(p.toString()); + } + return joiner.toString(); + } + + /** + * Returns a hash code value for this type. + * + * @return a hash code value + */ + @Override + public int hashCode() { + return super.hashCode() + 37 * Objects.hashCode(moduleName); + } + + /** + * Compares this type with the given object for equality. + * + * @param obj the object to compare with this type + * @return whether the two objects are equal + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (super.equals(obj)) { + final JavaPathType other = (JavaPathType) obj; + return Objects.equals(moduleName, other.moduleName); + } + return false; + } +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java new file mode 100644 index 000000000000..3654dc34cd33 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java @@ -0,0 +1,142 @@ +/* + * 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. + * + *

Path types are often exclusive. For example, a dependency should not be both + * on the Java class-path and on the Java module-path.

+ * + * @see org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths() + * + * @since 4.0.0 + */ +@Experimental +public abstract class PathType { + /** + * The programmatic name of this path type. + */ + @Nonnull + private final String name; + + /** + * The tools option for this path, or {@code null} if none. + * + * @see #option() + */ + final String option; + + /** + * Creates a new enumeration value for a path associated to the given tool option. + * + * @param name the programmatic name of this path type + * @param option the tool option for this path, or {@code null} if none + */ + protected PathType(final String name, final String option) { + this.name = Objects.requireNonNull(name); + this.option = option; + } + + /** + * Returns the programmatic name of this path type. For example, if this path type + * is {@link JavaPathType#MODULES}, then this method returns {@code "MODULES"}. + * + * @return the programmatic name of this path type + * + * @see #toString() + */ + @Nonnull + public String name() { + return name; + } + + /** + * Returns the name of the tool option for this path. For example, if this path type + * is {@link JavaPathType#MODULES}, then this method returns {@code "--module-path"}. + * The option does not include the {@linkplain JavaPathType#moduleName() module name} + * on which it applies. + * + * @return the name of the tool option for this path type + */ + @Nonnull + public Optional option() { + return Optional.ofNullable(option); + } + + /** + * Returns the option followed by a string representation of the given path elements. + * The path elements are separated by an option-specific or platform-specific separator. + * If the given {@code paths} argument contains no element, then this method returns an empty string. + * + * @param paths the path to format as a string + * @return the option associated to this path type followed by the given path elements, + * or an empty string if there is no path element. + */ + @Nonnull + public abstract String option(Iterable paths); + + /** + * Returns the programmatic name of this path type, including the class name. For example, + * if this type is {@link JavaPathType#MODULES}, then this method returns {@code "JavaPathType.MODULES"}. + * + * @return the programmatic name of this path type + */ + @Nonnull + @Override + public String toString() { + return getClass().getSimpleName() + '.' + name; + } + + /** + * Returns a hash code value for this type. + * + * @return a hash code value + */ + @Override + public int hashCode() { + return getClass().hashCode() + name.hashCode() + 31 * Objects.hashCode(option); + } + + /** + * Compares this type with the given object for equality. + * + * @param obj the object to compare with this type + * @return whether the two objects are equal + */ + @Override + public boolean equals(final Object obj) { + if (obj != null && obj.getClass() == getClass()) { + final PathType other = (PathType) obj; + return name.equals(other.name) && Objects.equals(option, other.option); + } + return false; + } +} 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 793243850068..9230207445c7 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 @@ -21,9 +21,11 @@ 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.Node; +import org.apache.maven.api.PathType; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; @@ -32,13 +34,57 @@ public interface DependencyResolverResult extends DependencyCollectorResult { /** * The ordered list of the flattened dependency nodes. + * + * @return the ordered list of the flattened dependency nodes */ @Nonnull List getNodes(); + /** + * Returns the file paths of all dependencies, regardless on which tool option those paths should be placed. + * The returned list may contain a mix of Java class-path, Java module-path, and other types of path elements. + * + * @return the paths of all dependencies + */ @Nonnull List getPaths(); + /** + * Returns the file paths of all dependencies, dispatched according the tool options where to place them. + * The {@link PathType} keys identify, for example, {@code --class-path} or {@code --module-path} options. + * In the case of Java tools, the map may also contain {@code --patch-module} options, which are + * {@linkplain org.apache.maven.api.JavaPathType#patchModule(String) handled in a special way}. + * + *

Design note

+ * All types of path are determined together because they are sometime mutually exclusive. + * For example, an artifact of type {@value org.apache.maven.api.Type#JAR} can be placed + * either on the class-path or on the module-path. The project needs to make a choice + * (possibly using heuristic rules), then to add the dependency in only one of the options + * identified by {@link PathType}. + * + * @return file paths to place on the different tool options + */ + @Nonnull + Map> getDispatchedPaths(); + @Nonnull Map getDependencies(); + + /** + * Formats the command-line option for the path of the specified type. + * The option are documented in {@link org.apache.maven.api.JavaPathType} enumeration values. + * + * @param type the desired type of path (class-path, module-path, …) + * @return the option to pass to Java tools + */ + default Optional formatOption(final PathType type) { + List paths = getDispatchedPaths().get(type); + if (paths != null) { + String option = type.option(paths); + if (!option.isEmpty()) { + return Optional.of(option); + } + } + return Optional.empty(); + } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java index c5ba1a32b02d..98b9a84746d9 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java @@ -75,43 +75,49 @@ private static DependencyFilter getScopeDependencyFilter(ResolutionScope scope) }; } + /** + * Collects, flattens and resolves the dependencies. + * + * @param request the request to resolve + * @return the result of the resolution + */ @Override - public DependencyResolverResult resolve(DependencyResolverRequest request) + public DependencyResolverResult resolve(final DependencyResolverRequest request) throws DependencyCollectorException, DependencyResolverException, ArtifactResolverException { - nonNull(request, "request can not be null"); - InternalSession session = InternalSession.from(request.getSession()); + nonNull(request, "request"); + final InternalSession session = InternalSession.from(request.getSession()); if (request.getProject().isPresent()) { - DependencyResolutionResult result = resolveDependencies( + final DependencyResolutionResult resolved = resolveDependencies( request.getSession(), request.getProject().get(), request.getResolutionScope()); - Map nodes = stream( - result.getDependencyGraph()) + final Map nodes = stream( + resolved.getDependencyGraph()) .filter(n -> n.getDependency() != null) .collect(Collectors.toMap(DependencyNode::getDependency, n -> n)); - Node root = session.getNode(result.getDependencyGraph()); + final Node root = session.getNode(resolved.getDependencyGraph()); List dependencies = new ArrayList<>(); Map artifacts = new LinkedHashMap<>(); List paths = new ArrayList<>(); - for (org.eclipse.aether.graph.Dependency dep : result.getResolvedDependencies()) { + for (org.eclipse.aether.graph.Dependency dep : resolved.getResolvedDependencies()) { dependencies.add(session.getNode(nodes.get(dep))); Path path = dep.getArtifact().getFile().toPath(); artifacts.put(session.getDependency(dep), path); paths.add(path); } return new DefaultDependencyResolverResult( - result.getCollectionErrors(), root, dependencies, paths, artifacts); + resolved.getCollectionErrors(), root, dependencies, paths, artifacts); } - DependencyCollectorResult collectorResult = + final DependencyCollectorResult collectorResult = session.getService(DependencyCollector.class).collect(request); - List nodes = flatten(session, collectorResult.getRoot(), request.getResolutionScope()); + final List nodes = flatten(session, collectorResult.getRoot(), request.getResolutionScope()); List deps = nodes.stream().map(Node::getDependency).filter(Objects::nonNull).collect(Collectors.toList()); List coordinates = deps.stream().map(Artifact::toCoordinate).collect(Collectors.toList()); - Map artifacts = session.resolveArtifacts(coordinates); + final Map artifacts = session.resolveArtifacts(coordinates); Map dependencies = new LinkedHashMap<>(); List paths = new ArrayList<>(); for (Dependency d : deps) { @@ -126,11 +132,12 @@ public DependencyResolverResult resolve(DependencyResolverRequest request) collectorResult.getExceptions(), collectorResult.getRoot(), nodes, paths, dependencies); } - private Stream stream(DependencyNode node) { - return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(this::stream)); + private static Stream stream(final DependencyNode node) { + return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(DefaultDependencyResolver::stream)); } - private DependencyResolutionResult resolveDependencies(Session session, Project project, ResolutionScope scope) { + private static DependencyResolutionResult resolveDependencies( + final Session session, final Project project, final ResolutionScope scope) { Collection toResolve = toScopes(scope); try { LifecycleDependencyResolver lifecycleDependencyResolver = @@ -147,57 +154,11 @@ private DependencyResolutionResult resolveDependencies(Session session, Project } } - private MavenProject getMavenProject(Project project) { + private static MavenProject getMavenProject(final Project project) { return ((DefaultProject) project).getProject(); } - private Collection toScopes(ResolutionScope scope) { + private static Collection toScopes(final ResolutionScope scope) { return map(scope.scopes(), Scope::id); } - - static class DefaultDependencyResolverResult implements DependencyResolverResult { - private final List exceptions; - private final Node root; - private final List nodes; - private final List paths; - private final Map dependencies; - - DefaultDependencyResolverResult( - List exceptions, - Node root, - List nodes, - List paths, - Map dependencies) { - this.exceptions = exceptions; - this.root = root; - this.nodes = nodes; - this.paths = paths; - this.dependencies = dependencies; - } - - @Override - public List getExceptions() { - return exceptions; - } - - @Override - public Node getRoot() { - return root; - } - - @Override - public List getNodes() { - return nodes; - } - - @Override - public List getPaths() { - return paths; - } - - @Override - public Map getDependencies() { - return dependencies; - } - } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java new file mode 100644 index 000000000000..a884e578b929 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java @@ -0,0 +1,108 @@ +/* + * 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.internal.impl; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import org.apache.maven.api.Dependency; +import org.apache.maven.api.Node; +import org.apache.maven.api.PathType; +import org.apache.maven.api.services.DependencyResolverResult; + +/** + * The result of collecting dependencies with a dependency resolver. + * + * @see DefaultDependencyResolver#resolve(DependencyResolverRequest) + */ +final class DefaultDependencyResolverResult implements DependencyResolverResult { + /** + * The exceptions that occurred while building the dependency graph. + */ + private final List exceptions; + + /** + * The root node of the dependency graph. + */ + private final Node root; + + /** + * The ordered list of the flattened dependency nodes. + */ + private final List nodes; + + /** + * The file paths of all dependencies, regardless on which Java tool option those paths should be placed. + */ + private final List paths; + + /** + * The dependencies together with the path to each dependency. + */ + private final Map dependencies; + + /** + * + * @param exceptions the exceptions that occurred while building the dependency graph + * @param root the root node of the dependency graph + */ + DefaultDependencyResolverResult( + List exceptions, + Node root, + List nodes, + List paths, + Map dependencies) { + this.exceptions = exceptions; + this.root = root; + this.nodes = nodes; + this.paths = paths; + this.dependencies = dependencies; + } + + @Override + public List getExceptions() { + return exceptions; + } + + @Override + public Node getRoot() { + return root; + } + + @Override + public List getNodes() { + return nodes; + } + + @Override + public List getPaths() { + return paths; + } + + @Override + public Map> getDispatchedPaths() { + throw new UnsupportedOperationException("Not yet implemented."); + } + + @Override + public Map getDependencies() { + return dependencies; + } +} From b709b5f40cdff7cc5ca5ecbbd816828b5b1ac2d6 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Mon, 8 Jan 2024 01:49:25 +0100 Subject: [PATCH 04/31] [MNG-8015] Control the type of path where each dependency can be placed - Add a `DependencyProperties.PATH_TYPES` property. - Deprecate `DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT` and `isAddedToClasspath()` methods. - Add documentation for explaining better the context-sensitive interpretation of path constituents. --- .../maven/api/DependencyProperties.java | 17 ++++++++++ .../org/apache/maven/api/JavaPathType.java | 33 +++++++++++++++++++ .../java/org/apache/maven/api/PathType.java | 1 + .../main/java/org/apache/maven/api/Type.java | 13 +++++--- .../artifact/handler/ArtifactHandler.java | 11 +++++++ .../artifact/handler/ArtifactHandlerMock.java | 2 ++ .../maven/repository/TestArtifactHandler.java | 1 + .../handler/DefaultArtifactHandler.java | 3 ++ .../impl/DefaultDependencyProperties.java | 24 ++++++++++++++ .../impl/TransformedArtifactHandler.java | 1 + .../apache/maven/project/MavenProject.java | 12 +++++++ .../project/artifact/PluginArtifact.java | 1 + .../project/artifact/ProjectArtifact.java | 1 + .../internal/impl/TestArtifactHandler.java | 1 + 14 files changed, 117 insertions(+), 4 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java index 16f25334094d..32668e4ab586 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java @@ -187,6 +187,20 @@ public boolean equals(Object obj) { */ Key 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. + * + *

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}.

+ */ + Key PATH_TYPES = new Key<>("pathTypes", PathType[].class).intern(); + /** * Boolean flag telling that dependency contains all of its dependencies. *

@@ -196,7 +210,10 @@ public boolean equals(Object obj) { /** * Boolean flag telling that dependency is meant to be placed on class path. + * + * @deprecated Use {@link #PATH_TYPES} and {@link JavaPathType#CLASSES} instead. */ + @Deprecated Key FLAG_CLASS_PATH_CONSTITUENT = new Key<>("classPathConstituent", Boolean.class).intern(); /** diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java index e936a8158eb5..56f1a69d340e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java @@ -50,12 +50,40 @@ public final class JavaPathType extends PathType { /** * The path identified by the Java {@code --class-path} option. * Used for compilation, execution and Javadoc among others. + * + *

Context-sensitive interpretation

+ * 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: + * + *
    + *
  • 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).
  • + *
  • 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.
  • + *
*/ 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. + * + *

Context-sensitive interpretation

+ * 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: + * + *
    + *
  • If {@link #CLASSES} path type is also set, then the dependency should 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.
  • + *
  • 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.
  • + *
*/ public static final JavaPathType MODULES = new JavaPathType("MODULES", "--module-path", null); @@ -104,6 +132,11 @@ public final class JavaPathType extends PathType { * Contrarily to the other types of paths, this path is applied to only * one specific module. Used for compilation and execution among others. * + *

Context-sensitive interpretation

+ * This path type makes sense only when a main module is added on the module-path by another dependency. + * In no main module is found, the patch dependency may be added on the class-path or module-path + * depending on whether {@link #CLASSES} or {@link #MODULES} is present. + * * @param moduleName name of the module on which to apply the path * @return an identification of the patch-module path for the given module. * diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java index 3654dc34cd33..27dd04de7a13 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java @@ -35,6 +35,7 @@ *

Path types are often exclusive. For example, a dependency should not be both * on the Java class-path and on the Java module-path.

* + * @see DependencyProperties#PATH_TYPES * @see org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths() * * @since 4.0.0 diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java index 15ffc0b59a69..cac62e5b395e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java @@ -30,7 +30,7 @@ *

* It provides information about the file type (or extension) of the associated artifact, * its default classifier, and how the artifact will be used in the build when creating - * classpaths. + * class-paths or module-paths. *

* For example, the type {@code java-source} has a {@code jar} extension and a * {@code sources} classifier. The artifact and its dependencies should be added @@ -80,11 +80,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 should be added to the classpath depends on other + * {@linkplain #getDependencyProperties() dependency properties}. * - * @return if the artifact should be added to the class path + * @return if the artifact can be added to the class path + * + * @deprecated A value of {@code true} does not mean that the dependency should + * be placed on the classpath. See {@link JavaPathType} instead for better analysis. */ + @Deprecated default boolean isAddedToClassPath() { return getDependencyProperties().checkFlag(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT); } diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java b/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java index 92cca2a069dd..12f50ef31a76 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java @@ -53,5 +53,16 @@ public interface ArtifactHandler { String getLanguage(); + /** + * Specifies if the artifact contains java classes and can be added to the classpath. + * Whether the artifact should be added to the classpath depends on other + * dependency properties. + * + * @return if the artifact can be added to the class path + * + * @deprecated A value of {@code true} does not mean that the dependency should + * be placed on the classpath. See {@code JavaPathType} instead for better analysis. + */ + @Deprecated boolean isAddedToClasspath(); } diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java b/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java index 8f8dd820e0cf..f70db5bcbd32 100644 --- a/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java +++ b/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java @@ -77,11 +77,13 @@ public String getLanguage() { return language; } + @Deprecated public void setAddedToClasspath(boolean addedToClasspath) { this.addedToClasspath = addedToClasspath; } @Override + @Deprecated public boolean isAddedToClasspath() { return addedToClasspath; } diff --git a/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java b/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java index 5e02488d0716..93c90bd889fa 100644 --- a/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java +++ b/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java @@ -65,6 +65,7 @@ public String getPackaging() { } @Override + @Deprecated public boolean isAddedToClasspath() { return true; } diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java index 0a083732c05d..198fe6fb6aa3 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java @@ -37,6 +37,7 @@ public class DefaultArtifactHandler implements ArtifactHandler { private String language; + @Deprecated private boolean addedToClasspath; /** @@ -146,10 +147,12 @@ public void setLanguage(final String language) { } @Override + @Deprecated public boolean isAddedToClasspath() { return addedToClasspath; } + @Deprecated public void setAddedToClasspath(final boolean addedToClasspath) { this.addedToClasspath = addedToClasspath; } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java index a3147b889e6e..966cbf8cff4e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java @@ -24,6 +24,8 @@ import java.util.Set; import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.PathType; import org.apache.maven.api.annotations.Nonnull; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -141,6 +143,7 @@ public DefaultDependencyProperties build() { */ protected DefaultDependencyProperties(@Nonnull final Map, Object> properties) { this.properties = nonNull(properties, "properties"); + addCompatibility(); } /** @@ -155,6 +158,27 @@ public DefaultDependencyProperties(@Nonnull Key... flags) { for (Key flag : flags) { properties.put(flag, Boolean.TRUE); } + addCompatibility(); + } + + /** + * @deprecated Bridge with deprecated flag. To be removed if deprecated flag is removed. + */ + @Deprecated + private void addCompatibility() { + PathType[] types = get(PATH_TYPES); + if (types != null) { + boolean found = false; + for (PathType type : types) { + if (type.equals(JavaPathType.CLASSES)) { + found = true; + break; + } + } + properties.put(FLAG_CLASS_PATH_CONSTITUENT, found); + } else if (checkFlag(FLAG_CLASS_PATH_CONSTITUENT)) { + properties.put(PATH_TYPES, new PathType[] {JavaPathType.CLASSES}); + } } /** diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java index b2a1f9c2742b..64087c262d47 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java @@ -62,6 +62,7 @@ public String getPackaging() { } @Override + @Deprecated public boolean isAddedToClasspath() { return false; } diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java index 854344497493..9b58e0212646 100644 --- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java +++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java @@ -378,7 +378,11 @@ private List getClasspathElements(final Predicate scopeFilter, f * This method can be invoked when the caller does not support module-path. * * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + * + * @deprecated This method is unreliable because it does not consider other dependency properties. + * See {@link org.apache.maven.api.JavaPathType} instead for better analysis. */ + @Deprecated public List getCompileClasspathElements() throws DependencyResolutionRequiredException { return getClasspathElements(MavenProject::isCompilePathElement, false); } @@ -388,7 +392,11 @@ public List getCompileClasspathElements() throws DependencyResolutionReq * This method can be invoked when the caller does not support module-path. * * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + * + * @deprecated This method is unreliable because it does not consider other dependency properties. + * See {@link org.apache.maven.api.JavaPathType} instead for better analysis. */ + @Deprecated public List getTestClasspathElements() throws DependencyResolutionRequiredException { return getClasspathElements(MavenProject::isTestPathElement, true); } @@ -398,7 +406,11 @@ public List getTestClasspathElements() throws DependencyResolutionRequir * This method can be invoked when the caller does not support module-path. * * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + * + * @deprecated This method is unreliable because it does not consider other dependency properties. + * See {@link org.apache.maven.api.JavaPathType} instead for better analysis. */ + @Deprecated public List getRuntimeClasspathElements() throws DependencyResolutionRequiredException { return getClasspathElements(MavenProject::isRuntimePathElement, false); } diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java index bf266e717fc0..18c3442d0635 100644 --- a/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java +++ b/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java @@ -83,6 +83,7 @@ public String getPackaging() { } @Override + @Deprecated public boolean isAddedToClasspath() { return true; } diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java index 965b37097017..c040fc93446e 100644 --- a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java +++ b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java @@ -88,6 +88,7 @@ public String getPackaging() { } @Override + @Deprecated public boolean isAddedToClasspath() { return false; } diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java index 68281e9169c9..30ebee3972d8 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java +++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java @@ -65,6 +65,7 @@ public String getPackaging() { } @Override + @Deprecated public boolean isAddedToClasspath() { return true; } From 9c5e9ff412718e4ad29299ea79ba0d158c27d43d Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Mon, 8 Jan 2024 03:10:22 +0100 Subject: [PATCH 05/31] [MNG-8015] Control the type of path where each dependency can be placed - Added implementation of `DependencyResolverResult.getDispatchedPaths()`. - The code in `DefaultDependencyResolver` has been refactored, but the new code should be equivalent to the previous code for the collections that existed before this commit. The significant changes are the new code for computing the new `dispatchedPaths` map. --- .../services/DependencyResolverRequest.java | 42 ++- .../impl/DefaultDependencyResolver.java | 61 ++-- .../impl/DefaultDependencyResolverResult.java | 264 +++++++++++++++++- .../internal/impl/PathModularization.java | 264 ++++++++++++++++++ .../impl/PathModularizationCache.java | 137 +++++++++ 5 files changed, 729 insertions(+), 39 deletions(-) create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java index 0519ececf1d7..091431397ac2 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java @@ -20,9 +20,12 @@ import java.util.Collection; import java.util.List; +import java.util.function.Predicate; import org.apache.maven.api.Artifact; import org.apache.maven.api.DependencyCoordinate; +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.PathType; import org.apache.maven.api.Project; import org.apache.maven.api.ResolutionScope; import org.apache.maven.api.Session; @@ -37,6 +40,14 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest { @Nonnull ResolutionScope getResolutionScope(); + /** + * {@return a filter for the types of path (class-path, module-path, …) accepted by the tool}. + * For example, if a Java tools accepts only class-path elements, then the filter should return + * {@code true} for {@link JavaPathType#CLASSES} and {@code false} for {@link JavaPathType#MODULES}. + * If no filter is explicitly set, then the default is a filter accepting everything. + */ + Predicate getPathTypeFilter(); + @Nonnull static DependencyResolverRequestBuilder builder() { return new DependencyResolverRequestBuilder(); @@ -87,7 +98,9 @@ static DependencyResolverRequest build( @NotThreadSafe class DependencyResolverRequestBuilder extends DependencyCollectorRequestBuilder { - ResolutionScope resolutionScope; + private ResolutionScope resolutionScope; + + private Predicate pathTypeFilter; @Nonnull @Override @@ -159,16 +172,32 @@ public DependencyResolverRequestBuilder resolutionScope(@Nonnull ResolutionScope return this; } + @Nonnull + public DependencyResolverRequestBuilder pathTypeFilter(@Nonnull Predicate pathTypeFilter) { + this.pathTypeFilter = pathTypeFilter; + return this; + } + @Override public DependencyResolverRequest build() { return new DefaultDependencyResolverRequest( - session, project, rootArtifact, root, dependencies, managedDependencies, verbose, resolutionScope); + session, + project, + rootArtifact, + root, + dependencies, + managedDependencies, + verbose, + resolutionScope, + pathTypeFilter); } static class DefaultDependencyResolverRequest extends DefaultDependencyCollectorRequest implements DependencyResolverRequest { private final ResolutionScope resolutionScope; + private final Predicate pathTypeFilter; + DefaultDependencyResolverRequest( Session session, Project project, @@ -177,9 +206,11 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector Collection dependencies, Collection managedDependencies, boolean verbose, - ResolutionScope resolutionScope) { + ResolutionScope resolutionScope, + Predicate pathTypeFilter) { super(session, project, rootArtifact, root, dependencies, managedDependencies, verbose); this.resolutionScope = nonNull(resolutionScope, "resolutionScope cannot be null"); + this.pathTypeFilter = (pathTypeFilter != null) ? pathTypeFilter : (t) -> true; if (verbose) { throw new IllegalArgumentException("verbose cannot be true for resolving dependencies"); } @@ -190,6 +221,11 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector public ResolutionScope getResolutionScope() { return resolutionScope; } + + @Override + public Predicate getPathTypeFilter() { + return pathTypeFilter; + } } } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java index 98b9a84746d9..ad74d332b4e2 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java @@ -21,15 +21,15 @@ import javax.inject.Named; import javax.inject.Singleton; +import java.io.IOException; import java.nio.file.Path; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -37,6 +37,7 @@ import org.apache.maven.api.ArtifactCoordinate; import org.apache.maven.api.Dependency; import org.apache.maven.api.Node; +import org.apache.maven.api.PathType; import org.apache.maven.api.Project; import org.apache.maven.api.ResolutionScope; import org.apache.maven.api.Scope; @@ -86,7 +87,8 @@ public DependencyResolverResult resolve(final DependencyResolverRequest request) throws DependencyCollectorException, DependencyResolverException, ArtifactResolverException { nonNull(request, "request"); final InternalSession session = InternalSession.from(request.getSession()); - + final Predicate filter = request.getPathTypeFilter(); + final PathModularizationCache cache = new PathModularizationCache(); // TODO: should be project-wide cache. if (request.getProject().isPresent()) { final DependencyResolutionResult resolved = resolveDependencies( request.getSession(), request.getProject().get(), request.getResolutionScope()); @@ -97,39 +99,42 @@ public DependencyResolverResult resolve(final DependencyResolverRequest request) .collect(Collectors.toMap(DependencyNode::getDependency, n -> n)); final Node root = session.getNode(resolved.getDependencyGraph()); - List dependencies = new ArrayList<>(); - Map artifacts = new LinkedHashMap<>(); - List paths = new ArrayList<>(); - for (org.eclipse.aether.graph.Dependency dep : resolved.getResolvedDependencies()) { - dependencies.add(session.getNode(nodes.get(dep))); + final List deprendencies = resolved.getResolvedDependencies(); + final DefaultDependencyResolverResult result = + new DefaultDependencyResolverResult(resolved.getCollectionErrors(), root, deprendencies.size()); + for (org.eclipse.aether.graph.Dependency dep : deprendencies) { + Node node = session.getNode(nodes.get(dep)); Path path = dep.getArtifact().getFile().toPath(); - artifacts.put(session.getDependency(dep), path); - paths.add(path); + try { + result.addDependency(node, session.getDependency(dep), filter, path, cache); + } catch (IOException e) { + throw cannotReadModuleInfo(path, e); + } } - return new DefaultDependencyResolverResult( - resolved.getCollectionErrors(), root, dependencies, paths, artifacts); + return result; } final DependencyCollectorResult collectorResult = session.getService(DependencyCollector.class).collect(request); final List nodes = flatten(session, collectorResult.getRoot(), request.getResolutionScope()); - List deps = - nodes.stream().map(Node::getDependency).filter(Objects::nonNull).collect(Collectors.toList()); - List coordinates = - deps.stream().map(Artifact::toCoordinate).collect(Collectors.toList()); + final List coordinates = nodes.stream() + .map(Node::getDependency) + .filter(Objects::nonNull) + .map(Artifact::toCoordinate) + .collect(Collectors.toList()); final Map artifacts = session.resolveArtifacts(coordinates); - Map dependencies = new LinkedHashMap<>(); - List paths = new ArrayList<>(); - for (Dependency d : deps) { - Path path = artifacts.get(d); - if (dependencies.put(d, path) != null) { - throw new IllegalStateException("Duplicate key"); + final DefaultDependencyResolverResult result = new DefaultDependencyResolverResult( + collectorResult.getExceptions(), collectorResult.getRoot(), nodes.size()); + for (Node node : nodes) { + Dependency d = node.getDependency(); + Path path = (d != null) ? artifacts.get(d) : null; + try { + result.addDependency(node, d, filter, path, cache); + } catch (IOException e) { + throw cannotReadModuleInfo(path, e); } - paths.add(path); } - - return new DefaultDependencyResolverResult( - collectorResult.getExceptions(), collectorResult.getRoot(), nodes, paths, dependencies); + return result; } private static Stream stream(final DependencyNode node) { @@ -161,4 +166,8 @@ private static MavenProject getMavenProject(final Project project) { private static Collection toScopes(final ResolutionScope scope) { return map(scope.scopes(), Scope::id); } + + private static DependencyResolverException cannotReadModuleInfo(final Path path, final IOException cause) { + return new DependencyResolverException("Cannot read module information of " + path, cause); + } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java index a884e578b929..853bc953435f 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java @@ -18,17 +18,33 @@ */ package org.apache.maven.internal.impl; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; import org.apache.maven.api.Dependency; +import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Node; import org.apache.maven.api.PathType; import org.apache.maven.api.services.DependencyResolverResult; /** * The result of collecting dependencies with a dependency resolver. + * New instances are initially empty. Callers must populate with calls + * to the following methods, in that order: + * + *

    + *
  • {@link #addOutputDirectory(Path, Path, PathModularizationCache)} (optional)
  • + *
  • {@link #addDependency(Node, Dependency, Set, Path, PathModularizationCache)}
  • + *
* * @see DefaultDependencyResolver#resolve(DependencyResolverRequest) */ @@ -53,27 +69,255 @@ final class DefaultDependencyResolverResult implements DependencyResolverResult */ private final List paths; + /** + * The file paths of all dependencies, dispatched according the Java options where to place them. + */ + private final Map> dispatchedPaths; + /** * The dependencies together with the path to each dependency. */ private final Map dependencies; /** + * Information about modules in the main output. This field is initially null and is set to a non-null + * value when the output directories have been set, or when it is too late for setting them. + */ + private PathModularization outputModules; + + /** + * Creates an initially empty result. Callers should add path elements by calls + * to {@link #addDependency(Node, Dependency, Path, PathModularizationCache)}. * * @param exceptions the exceptions that occurred while building the dependency graph * @param root the root node of the dependency graph + * @param count estimated number of dependencies */ - DefaultDependencyResolverResult( - List exceptions, - Node root, - List nodes, - List paths, - Map dependencies) { + DefaultDependencyResolverResult(final List exceptions, final Node root, final int count) { this.exceptions = exceptions; this.root = root; - this.nodes = nodes; - this.paths = paths; - this.dependencies = dependencies; + nodes = new ArrayList<>(count); + paths = new ArrayList<>(count); + dispatchedPaths = new LinkedHashMap<>(); + dependencies = new LinkedHashMap<>(count + count / 3); + } + + /** + * Adds the given path element to the specified type of path. + * + * @param type the type of path (class-path, module-path, …) + * @param path the path element to add + */ + private void addPathElement(final PathType type, final Path path) { + dispatchedPaths.computeIfAbsent(type, (t) -> new ArrayList<>()).add(path); + } + + /** + * Adds main and test output directories to the result. This method adds the main output directory + * to the module-path if it contains a {@code module-info.class}, or to the class-path otherwise. + * For the test output directory, the rules are more complex and are governed by the fact that + * Java does not accept the placement of two modules of the same name on the module-path. + * So the modular test output directory usually needs to be placed in a {@code --path-module} option. + * + *
    + *
  • If the test output directory is modular, then: + *
      + *
    • If a test module name is identical to a main module name, + * place the test directory in a {@code --patch-module} option.
    • + *
    • Otherwise, place the test directory on the module-path. However, this case + * (a module existing only in test output, not in main output) should be uncommon.
    • + *
    + *
  • + *
  • Otherwise (test output contains no module information), then: + *
      + *
    • If the main output is on the module-path, place the test output + * on a {@code --patch-module} option.
    • + *
    • Otherwise (main output on the class-path), place the test output on the class-path too.
    • + *
    + *
  • + *
+ * + * This method must be invoked before {@link #addDependency(Node, Dependency, Path)} + * if output directories are desired on the class-path or module-path. + * This method can be invoked at most once. + * + * @param main the main output directory, or {@code null} if none + * @param test the test output directory, or {@code null} if none + * @param cache cache of module information about each dependency + * @throws IOException if an error occurred while reading module information + */ + void addOutputDirectory(final Path main, final Path test, final PathModularizationCache cache) throws IOException { + if (outputModules != null) { + throw new IllegalStateException("Output directories must be set first and only once."); + } + if (main != null) { + outputModules = cache.getModuleInfo(main); + addPathElement(outputModules.getPathType(), main); + } else { + outputModules = PathModularization.NONE; + } + if (test != null) { + boolean addToClasspath = true; + final PathModularization testModules = cache.getModuleInfo(test); + final boolean isModuleHierarchy = outputModules.isModuleHierarchy() || testModules.isModuleHierarchy(); + for (final String moduleName : outputModules.getModuleNames().values()) { + Path subdir = test; + if (isModuleHierarchy) { + // If module hierarchy is used, the directory names shall be the module names. + final Path path = test.resolve(moduleName); + if (!Files.isDirectory(path)) { + // Main module without tests. It is okay. + continue; + } + subdir = path; + } + // When the same module is found in main and test output, the latter is patching the former. + addPathElement(JavaPathType.patchModule(moduleName), subdir); + addToClasspath = false; + } + /* + * 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 (final Map.Entry entry : + testModules.getModuleNames().entrySet()) { + if (!outputModules.containsModule(entry.getValue())) { + addPathElement(JavaPathType.MODULES, entry.getKey()); + addToClasspath = false; + } + } + if (addToClasspath) { + addPathElement(JavaPathType.CLASSES, test); + } + } + } + + /** + * Adds a dependency to the result. This method populates the {@link #nodes}, {@link #paths}, + * {@link #dispatchedPaths} and {@link #dependencies} collections with the given arguments. + * + * @param node the dependency node + * @param dep the dependency for the given node, or {@code null} if none + * @param filter filter the paths accepted by the tool which will consume the path. + * @param path the path to the dependency, or {@code null} if the dependency was null + * @param cache cache of module information about each dependency + * @throws IOException if an error occurred while reading module information + */ + void addDependency( + final Node node, + final Dependency dep, + final Predicate filter, + final Path path, + final PathModularizationCache cache) + throws IOException { + nodes.add(node); + if (dep == null) { + return; + } + if (dependencies.put(dep, path) != null) { + throw new IllegalStateException("Duplicated key: " + dep); + } + if (path == null) { + return; + } + paths.add(path); + /* + * Dispatch the dependency to class-path, module-path, patch-module path, etc. + * according the dependency properties. We need to process patch-module first, + * because this type depends on whether a module of the same name has already + * been added on the module-type. + */ + final DependencyProperties properties = dep.getDependencyProperties(); + final PathType[] pathTypes = properties.get(DependencyProperties.PATH_TYPES); + if (containsPatches(pathTypes)) { + if (outputModules == null) { + // For telling users that it is too late for setting the output directory. + outputModules = PathModularization.NONE; + } + PathType type = null; + for (Map.Entry info : + cache.getModuleInfo(path).getModuleNames().entrySet()) { + String moduleName = info.getValue(); + type = JavaPathType.patchModule(moduleName); + if (!containsModule(moduleName, cache)) { + /* + * Not patching an existing module. This case should be unusual. If it nevertheless + * happens, add on class-path or module-path if allowed, or keep patching otherwise. + * The latter case (keep patching) is okay if the main module will be defined later. + */ + type = cache.selectPathType(pathTypes, filter, path).orElse(type); + } + addPathElement(type, info.getKey()); + // There is usually no more than one element, but nevertheless allow multi-modules. + } + /* + * If the dependency has no module information, search for an artifact of the same groupId + * and artifactId. If one is found, we are patching that module. If none is found, add the + * dependency as a normal dependency. + */ + if (type == null) { + Path main = findArtifactPath(dep.getGroupId(), dep.getArtifactId()); + if (main != null) { + for (Map.Entry info : + cache.getModuleInfo(main).getModuleNames().entrySet()) { + type = JavaPathType.patchModule(info.getValue()); + addPathElement(type, info.getKey()); + // There is usually no more than one element, but nevertheless allow multi-modules. + } + } + } + if (type != null) { + return; // Dependency added, we are done. + } + } + cache.selectPathType(pathTypes, filter, path).ifPresent((type) -> addPathElement(type, path)); + } + + /** + * Returns whether the given array of path types contains at least one patch for a module. + */ + private boolean containsPatches(final PathType[] types) { + if (types != null) { + for (PathType type : types) { + if (type instanceof JavaPathType + && ((JavaPathType) type).moduleName().isPresent()) { + return true; + } + } + } + return false; + } + + /** + * Returns whether at least one previously added modular dependency contains a module of the given name. + * + * @param moduleName name of the module to search + * @param cache cache of module information about each dependency + */ + private boolean containsModule(final String moduleName, final PathModularizationCache cache) throws IOException { + for (Path path : dispatchedPaths.getOrDefault(JavaPathType.MODULES, Collections.emptyList())) { + if (cache.getModuleInfo(path).containsModule(moduleName)) { + return true; + } + } + return false; + } + + /** + * Searches an artifact of the given group and artifact identifiers, and returns its path + * + * @param group the group identifier to search + * @param artifact the artifact identifier to search + * @return path to the desired artifact, or {@code null} if not found + */ + private Path findArtifactPath(final String group, final String artifact) throws IOException { + for (final Map.Entry entry : dependencies.entrySet()) { + Dependency dep = entry.getKey(); + if (group.equals(dep.getGroupId()) && artifact.equals(dep.getArtifactId())) { + return entry.getValue(); + } + } + return null; } @Override @@ -98,7 +342,7 @@ public List getPaths() { @Override public Map> getDispatchedPaths() { - throw new UnsupportedOperationException("Not yet implemented."); + return dispatchedPaths; } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java new file mode 100644 index 000000000000..48436f33e857 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java @@ -0,0 +1,264 @@ +/* + * 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.internal.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; + +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Information about the modules contained in a path element. + * The path element may be a JAR file or a directory. Directories may use either package hierarchy + * or module hierarchy, but not module source hierarchy. The latter is excluded because this class + * is for path elements of compiled codes. + */ +final class PathModularization { + /** + * A unique constant for all non-modular dependencies. + */ + public static final PathModularization NONE = new PathModularization(); + + /** + * Name of the file to use as a sentinel value for deciding if a directory or a JAR is modular. + */ + private static final String MODULE_INFO = "module-info.class"; + + /** + * The attribute for automatic module name in {@code META-INF/MANIFEST.MF} files. + */ + private static final Attributes.Name AUTO_MODULE_NAME = new Attributes.Name("Automatic-Module-Name"); + + /** + * Module information 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. + * + *

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.

+ * + * @see #getModuleNames() + */ + private final Map 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; + + /** + * Constructs an empty instance for non-modular dependencies. + * + * @see #NONE + */ + private PathModularization() { + descriptors = Collections.emptyMap(); + isModuleHierarchy = false; + } + + /** + * Finds module information in the given JAR file, output directory, or test output directory. + * If no module is found, or if module information cannot be extracted, then this constructor + * builds an empty map. + * + *

If the {@code resolve} parameter value is {@code false}, then some or all map values may + * be null instead of the actual module name. This option can avoid the cost of reading module + * descriptors when only the modules existence needs to be verified.

+ * + *

Algorithm

+ * If the given path is a directory, then there is a choice: + *
    + *
  • Package hierarchy: if a {@code module-info.class} file is found at the root, + * then builds a singleton map with the module name declared in that descriptor.
  • + *
  • Module hierarchy: if {@code module-info.class} files are found in sub-directories, + * at a deep intentionally restricted to one level, then builds a map of module names found + * in the descriptor of each sub-directory.
  • + *
+ * + * Otherwise if the given path is a JAR file, then there is a choice: + *
    + *
  • If a {@code module-info.class} file is found in the root directory or in a + * {@code "META-INF/versions/{n}/"} subdirectory, builds a singleton map with + * the module name declared in that descriptor.
  • + *
  • Otherwise if an {@code "Automatic-Module-Name"} attribute is declared in the + * {@code META-INF/MANIFEST.MF} file, builds a singleton map with the value of that attribute.
  • + *
+ * + * Otherwise builds an empty map. + * + * @param path directory or JAR file to test + * @param resolve whether the module names are requested. If false, null values may be used instead + * @throws IOException if an error occurred while reading the JAR file or the module descriptor + */ + PathModularization(final Path path, final boolean resolve) throws IOException { + if (Files.isDirectory(path)) { + /* + * Package hierarchy: only one module with descriptor at the root. + * This is the layout of output directories in projects using the + * classical (Java 8 and before) way to organize source files. + */ + Path file = path.resolve(MODULE_INFO); + if (Files.isRegularFile(file)) { + String name = null; + if (resolve) { + try (InputStream in = Files.newInputStream(file)) { + name = getModuleName(in); + } + } + descriptors = Collections.singletonMap(file, name); + isModuleHierarchy = false; + return; + } + /* + * Module hierarchy: many modules, one per directory, with descriptor at the root of the sub-directory. + * This is the layout of output directories in projects using the new (Java 9 and later) way to organize + * source files. + */ + if (Files.isDirectory(file)) { + final Map names = new HashMap<>(); + try (Stream subdirs = Files.list(file)) { + subdirs.filter(Files::isDirectory).forEach((subdir) -> { + Path mf = subdir.resolve(MODULE_INFO); + if (Files.isRegularFile(mf)) { + String name = null; + if (resolve) { + try (InputStream in = Files.newInputStream(mf)) { + name = getModuleName(in); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + names.put(mf, name); + } + }); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + if (!names.isEmpty()) { + descriptors = Collections.unmodifiableMap(names); + isModuleHierarchy = true; + return; + } + } + } else if (Files.isRegularFile(path)) { + /* + * JAR file: can contain only one module, with descriptor at the root. + * If no descriptor, the "Automatic-Module-Name" manifest attribute is + * taken as a fallback. + */ + try (JarFile jar = new JarFile(path.toFile())) { + final ZipEntry entry = jar.getEntry(MODULE_INFO); + if (entry != null) { + String name = null; + if (resolve) { + try (InputStream in = jar.getInputStream(entry)) { + name = getModuleName(in); + } + } + descriptors = Collections.singletonMap(path, name); + isModuleHierarchy = false; + return; + } + // No module descriptor, check manifest file. + final Manifest mf = jar.getManifest(); + if (mf != null) { + final Object name = mf.getMainAttributes().get(AUTO_MODULE_NAME); + if (name instanceof String) { + descriptors = Collections.singletonMap(path, (String) name); + isModuleHierarchy = false; + return; + } + } + } + } + descriptors = Collections.emptyMap(); + isModuleHierarchy = false; + } + + /** + * Returns 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(final InputStream in) throws IOException { + return ModuleDescriptor.read(in).name(); + } + + /** + * Returns 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), + * or {@link JavaPathType#CLASSES} otherwise. A JAR file without module descriptor but with + * an "Automatic-Module-Name" manifest attribute is considered modular. + */ + public JavaPathType getPathType() { + return descriptors.isEmpty() ? JavaPathType.CLASSES : JavaPathType.MODULES; + } + + /** + * Returns whether module hierarchy was detected. If 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; + } + + /** + * Returns 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. + * + *

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.

+ */ + @Nonnull + public Map getModuleNames() { + return descriptors; + } + + /** + * Returns whether the dependency contains a module of the given name. + */ + public boolean containsModule(final String name) { + return descriptors.containsValue(name); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java new file mode 100644 index 000000000000..937c3826db07 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java @@ -0,0 +1,137 @@ +/* + * 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.internal.impl; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Predicate; + +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.PathType; + +/** + * Cache of {@link PathModularization} instances computed for given {@link Path} elements. + * The cache is used for avoiding the need to reopen the same files many times when the + * same dependency is used for different scope. For example a path used for compilation + * is typically also used for tests. + */ +final class PathModularizationCache { + /** + * Module information for each JAR file or output directories. + * Cached when first requested for avoiding to decode the module descriptors multiple times. + * + * @see #getModuleInfo(Path) + */ + private final Map moduleInfo; + + /** + * Whether JAR files are modular. This map is redundant with {@link #moduleInfo}, + * but cheaper to compute when the module names are not needed. + * + * @see #getPathType(Path) + */ + private final Map pathTypes; + + /** + * Creates an initially empty cache. + */ + PathModularizationCache() { + moduleInfo = new HashMap<>(); + pathTypes = new HashMap<>(); + } + + /** + * Gets module information for the given JAR file or output directory. + * Module descriptors are read when first requested, then cached. + */ + PathModularization getModuleInfo(final Path path) throws IOException { + PathModularization info = moduleInfo.get(path); + if (info == null) { + info = new PathModularization(path, true); + moduleInfo.put(path, info); + pathTypes.put(path, info.getPathType()); + } + return info; + } + + /** + * Returns {@link JavaPathType#MODULES} if the given JAR file or output directory is modular. + * This is used in heuristic rules for deciding whether to place a dependency on the class-path + * or on the module-path when the {@code "jar"} artifact type is used. + */ + private PathType getPathType(final Path path) throws IOException { + PathType type = pathTypes.get(path); + if (type == null) { + type = new PathModularization(path, false).getPathType(); + pathTypes.put(path, type); + } + return type; + } + + /** + * Selects the type of path where to place the given dependency. + * This method returns one of the values specified in the given array. + * This method does not handle the patch-module paths, because the patches + * depend on which modules have been previously added on the module-paths. + * + *

If the dependency can be a constituent of both the class-path and the module-path, + * then the path type is determined by checking if the dependency is modular.

+ * + * @param types types of path where a dependency can be placed, or {@code null} if unspecified + * @param filter filter the paths accepted by the tool which will consume the path. + * @param path path to the JAR file or output directory of the dependency + * @return where to place the dependency, or an empty value if the placement cannot be determined + * @throws IOException if an error occurred while reading module information + */ + Optional selectPathType(final PathType[] types, final Predicate filter, final Path path) + throws IOException { + if (types == null) { + return Optional.empty(); + } + PathType selected = null; + boolean classes = false; + boolean modules = false; + boolean unknown = false; + for (PathType type : types) { + if (filter.test(type)) { + if (JavaPathType.CLASSES.equals(type)) { + classes = true; + } else if (JavaPathType.MODULES.equals(type)) { + modules = true; + } else { + unknown = true; + } + if (selected == null) { + selected = type; + } else if (unknown) { + // More than one filtered value, and we don't know how to handle at least one of them. + // TODO: add a plugin mechanism for allowing plugin to specify their selection algorithm. + return Optional.empty(); + } + } + } + if (classes & modules) { + selected = getPathType(path); + } + return Optional.ofNullable(selected); + } +} From a646ab4794035d1dabbc8b8c774e4d99668c6dc0 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Mon, 8 Jan 2024 03:49:55 +0100 Subject: [PATCH 06/31] [MNG-8015] Control the type of path where each dependency can be placed Add types: - Type.MODULAR_JAR: unconditionally on the module-path. - Type.CLASSPATH_JAR: unconditionally on the class-path. - And more. --- .../org/apache/maven/api/JavaPathType.java | 9 ++++ .../main/java/org/apache/maven/api/Type.java | 49 ++++++++++++++++++ .../impl/DefaultDependencyResolverResult.java | 3 ++ .../maven/internal/impl/DefaultType.java | 11 ++++ .../impl/types/ClasspathJarTypeProvider.java | 50 +++++++++++++++++++ .../internal/impl/types/JarTypeProvider.java | 20 ++++---- .../impl/types/JavaSourceTypeProvider.java | 7 ++- .../impl/types/JavadocTypeProvider.java | 17 +++---- .../impl/types/MavenPluginTypeProvider.java | 17 +++---- .../impl/types/ModularJarTypeProvider.java | 50 +++++++++++++++++++ .../internal/impl/types/PomTypeProvider.java | 7 ++- .../impl/types/TestJarTypeProvider.java | 18 ++++--- 12 files changed, 221 insertions(+), 37 deletions(-) create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/types/ClasspathJarTypeProvider.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/types/ModularJarTypeProvider.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java index 56f1a69d340e..b432ea14a888 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java @@ -93,6 +93,15 @@ public final class JavaPathType extends PathType { public static final JavaPathType UPGRADE_MODULES = new JavaPathType("UPGRADE_MODULES", "--upgrade-module-path", null); + /** + * The path identified by the Java {@code --patch-module} option. + * Note that this option is incomplete, because it must be followed by a module name. + * Use this type only when the module to patch is unknown. + * + * @see #patchModule(String) + */ + public static final JavaPathType PATCH_MODULE = new JavaPathType("PATCH_MODULE", "--patch-module", null); + /** * The path identified by the Java {@code --processor-path} option. */ diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java index cac62e5b395e..6b3f7c15afb4 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java @@ -45,6 +45,55 @@ public interface Type { String LANGUAGE_NONE = "none"; String LANGUAGE_JAVA = "java"; + /** + * Artifact type name for a POM file. + */ + String POM = "pom"; + + /** + * Artifact type name for a JAR file that can be placed either on the class-path or on the module-path. + * The path (classes or modules) is chosen by the plugin, possibly using heuristic rules. + * This is the behavior of Maven 3. + */ + String JAR = "jar"; + + /** + * Artifact type name for a JAR file to unconditionally place on the class-path. + * If the JAR is modular, its module information are ignored. + * This type is new in Maven 4. + */ + String CLASSPATH_JAR = "classpath-jar"; + + /** + * Artifact type name for a JAR file to unconditionally place on the module-path. + * If the JAR is not modular, then it is loaded by Java as an unnamed module. + * This type is new in Maven 4. + */ + String MODULAR_JAR = "modular-jar"; + + /** + * Artifact type name for source code packaged in a JAR file. + */ + String JAVA_SOURCE = "java-source"; + + /** + * Artifact type name for javadoc packaged in a JAR file. + */ + String JAVADOC = "javadoc"; + + /** + * Artifact type name for a Maven plugin. + */ + String MAVEN_PLUGIN = "maven-plugin"; + + /** + * Artifact type name for a JAR file containing test classes. If the main artifact is placed on the class-path + * ({@value #JAR} or {@value #CLASSPATH_JAR} types), then the test artifact will also be placed on the class-path. + * Otherwise, if the main artifact is placed on the module-path ({@value #JAR} or {@value #MODULAR_JAR} types), + * then the test artifact will be added using {@code --patch-module} option. + */ + String TEST_JAR = "test-jar"; + /** * Returns the dependency type id. * The id uniquely identifies this dependency type. diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java index 853bc953435f..e45d624c7f64 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java @@ -279,6 +279,9 @@ void addDependency( private boolean containsPatches(final PathType[] types) { if (types != null) { for (PathType type : types) { + if (JavaPathType.PATCH_MODULE.equals(type)) { + return true; + } if (type instanceof JavaPathType && ((JavaPathType) type).moduleName().isPresent()) { return true; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java index 91ad258d6371..c71d784bf6dc 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java @@ -21,6 +21,7 @@ import java.util.Map; import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.PathType; import org.apache.maven.api.Type; import org.eclipse.aether.artifact.ArtifactType; @@ -51,6 +52,16 @@ public DefaultType( this.dependencyProperties = props.build(); } + public DefaultType(String id, String language, String extension, String classifier, PathType... pathTypes) { + this.extension = nonNull(extension, "extension"); + this.classifier = classifier; + dependencyProperties = new DefaultDependencyProperties.Builder() + .set(DependencyProperties.TYPE, id) + .set(DependencyProperties.LANGUAGE, language) + .set(DependencyProperties.PATH_TYPES, pathTypes) + .build(); + } + @Override public String getId() { return dependencyProperties.get(DependencyProperties.TYPE); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ClasspathJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ClasspathJarTypeProvider.java new file mode 100644 index 000000000000..365559f5d8f5 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ClasspathJarTypeProvider.java @@ -0,0 +1,50 @@ +/* + * 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.internal.impl.types; + +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.Type; +import org.apache.maven.internal.impl.DefaultType; + +/** + * Type provider for a JAR file to unconditionally place on the class-path. + * Dependencies of this type are class-path constituents only. + * + * @see Type#CLASSPATH_JAR + */ +@Named(ClasspathJarTypeProvider.NAME) +@Singleton +public class ClasspathJarTypeProvider implements Provider { + public static final String NAME = Type.CLASSPATH_JAR; + + private final Type type; + + public ClasspathJarTypeProvider() { + this.type = new DefaultType(NAME, Type.LANGUAGE_JAVA, "jar", null, JavaPathType.CLASSES); + } + + @Override + public Type get() { + return type; + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java index 974c34e0ed97..252692311eab 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java @@ -22,25 +22,27 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for a JAR file that can be placed either on the class-path or on the module-path. + * Dependencies of this type are class-path constituents and module-path constituents. + * Only one of those constituents shall be effective for any given dependency. + * The choice may depend on heuristic rules. + * + * @see Type#JAR + */ @Named(JarTypeProvider.NAME) @Singleton public class JarTypeProvider implements Provider { - public static final String NAME = "jar"; + public static final String NAME = Type.JAR; private final Type type; public JarTypeProvider() { - this.type = new DefaultType( - NAME, - Type.LANGUAGE_JAVA, - "jar", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Type.LANGUAGE_JAVA, "jar", null, JavaPathType.CLASSES, JavaPathType.MODULES); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java index bef8acf716fd..4cbadcc2f6ca 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java @@ -26,10 +26,15 @@ import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for source code packaged in a JAR file. + * + * @see Type#JAVA_SOURCE + */ @Named(JavaSourceTypeProvider.NAME) @Singleton public class JavaSourceTypeProvider implements Provider { - public static final String NAME = "java-source"; + public static final String NAME = Type.JAVA_SOURCE; private final Type type; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java index 1ccac4f04b49..2ae5b8d609c0 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java @@ -22,25 +22,24 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for javadoc packaged in a JAR file. + * + * @see Type#JAVADOC + */ @Named(JavadocTypeProvider.NAME) @Singleton public class JavadocTypeProvider implements Provider { - public static final String NAME = "javadoc"; + public static final String NAME = Type.JAVADOC; private final Type type; public JavadocTypeProvider() { - this.type = new DefaultType( - NAME, - Type.LANGUAGE_JAVA, - "jar", - "javadoc", - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Type.LANGUAGE_JAVA, "jar", "javadoc", JavaPathType.CLASSES); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java index bfdb424c2786..a2f6c1ec8a43 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java @@ -22,25 +22,24 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for a Maven plugin. + * + * @see Type#MAVEN_PLUGIN + */ @Named(MavenPluginTypeProvider.NAME) @Singleton public class MavenPluginTypeProvider implements Provider { - public static final String NAME = "maven-plugin"; + public static final String NAME = Type.MAVEN_PLUGIN; private final Type type; public MavenPluginTypeProvider() { - this.type = new DefaultType( - NAME, - Type.LANGUAGE_JAVA, - "jar", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Type.LANGUAGE_JAVA, "jar", null, JavaPathType.CLASSES); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ModularJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ModularJarTypeProvider.java new file mode 100644 index 000000000000..643766e38afd --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ModularJarTypeProvider.java @@ -0,0 +1,50 @@ +/* + * 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.internal.impl.types; + +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.Type; +import org.apache.maven.internal.impl.DefaultType; + +/** + * Type provider for a JAR file to unconditionally place on the module-path. + * Dependencies of this type are module-path constituents only. + * + * @see Type#MODULAR_JAR + */ +@Named(ModularJarTypeProvider.NAME) +@Singleton +public class ModularJarTypeProvider implements Provider { + public static final String NAME = Type.MODULAR_JAR; + + private final Type type; + + public ModularJarTypeProvider() { + this.type = new DefaultType(NAME, Type.LANGUAGE_JAVA, "jar", null, JavaPathType.MODULES); + } + + @Override + public Type get() { + return type; + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java index fe0f9705d0ea..b35dd998b954 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java @@ -26,10 +26,15 @@ import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for a POM file. + * + * @see Type#POM + */ @Named(PomTypeProvider.NAME) @Singleton public class PomTypeProvider implements Provider { - public static final String NAME = "pom"; + public static final String NAME = Type.POM; private final Type type; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java index 6bd7ea2da727..efa66564a71b 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java @@ -22,25 +22,27 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for a JAR file containing test classes. Dependencies of this type are class-path constituents + * or {@code --patch-module} option values. For any dependency, the choice depends on whether the main JAR file + * was placed on the class-path or module-path respectively. + * + * @see Type#TEST_JAR + */ @Named(TestJarTypeProvider.NAME) @Singleton public class TestJarTypeProvider implements Provider { - public static final String NAME = "test-jar"; + public static final String NAME = Type.TEST_JAR; private final Type type; public TestJarTypeProvider() { this.type = new DefaultType( - NAME, - Type.LANGUAGE_JAVA, - "jar", - "tests", - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + NAME, Type.LANGUAGE_JAVA, "jar", "tests", JavaPathType.CLASSES, JavaPathType.PATCH_MODULE); } @Override From de2d3538684f44bc664bf6cca05c01574394dc08 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sat, 20 Jan 2024 14:09:16 +0100 Subject: [PATCH 07/31] First round of pull request comments resolution: typos and minor changes in method signatures, removal of {@return} Javadoc tags for compatibility with older compilers. --- .../maven/api/DependencyProperties.java | 70 ++++++++++--------- .../org/apache/maven/api/JavaPathType.java | 14 ++-- .../main/java/org/apache/maven/api/Type.java | 1 + .../services/DependencyResolverRequest.java | 4 +- .../internal/impl/DefaultDependency.java | 4 +- .../impl/DefaultDependencyProperties.java | 27 ++++--- .../impl/DefaultDependencyResolverResult.java | 3 +- .../maven/internal/impl/DefaultType.java | 4 +- 8 files changed, 72 insertions(+), 55 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java index 32668e4ab586..56fbacbe3071 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java @@ -18,14 +18,17 @@ */ package org.apache.maven.api; -import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; /** * Dependency properties supported by Maven Core. @@ -48,7 +51,7 @@ class Key { * * @see #intern() */ - private static final Map> INTERNS = new HashMap<>(); + private static final ConcurrentMap> INTERNS = new ConcurrentHashMap<>(); /** * Value returned by {@link #name()}. @@ -68,35 +71,25 @@ class 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 valueType) { + public Key(@Nonnull String name, @Nonnull Class 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() + * @param name name of the key to search + * @return key for the given name */ - 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; + public static Optional> forName(@Nonnull String name) { + return Optional.ofNullable(INTERNS.get(name)); } /** - * {@return the name of the key}. + * Returns the name of the key. + * + * @return the name of the key */ @Nonnull public String name() { @@ -104,7 +97,9 @@ public String name() { } /** - * {@return the type of value associated to the key}. + * Returns the type of value associated to the key. + * + * @return the type of value associated to the key */ @Nonnull public Class valueType() { @@ -112,22 +107,20 @@ public Class valueType() { } /** - * {@return a canonical representation of this key}. A pool of keys, initially empty, is maintained privately. + * Returns 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. * + * @return a canonical representation of this key * @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 intern() { - Key previous; - synchronized (INTERNS) { - previous = INTERNS.putIfAbsent(name, this); - } + Key previous = INTERNS.putIfAbsent(name, this); if (previous == null) { return this; } @@ -138,8 +131,10 @@ public Key intern() { } /** - * {@return a string representation of this key}. + * Returns a string representation of this key. * By default, this is the name of this key. + * + * @return a string representation of this key */ @Override public String toString() { @@ -147,7 +142,9 @@ public String toString() { } /** - * {@return an hash code value for this key}. + * Returns an hash code value for this key}. + * + * @return an hash code value for this key */ @Override public int hashCode() { @@ -217,7 +214,9 @@ public boolean equals(Object obj) { Key FLAG_CLASS_PATH_CONSTITUENT = new Key<>("classPathConstituent", Boolean.class).intern(); /** - * {@return the keys of all properties in this map}. + * Returns the keys of all properties in this map. + * + * @return the keys of all properties in this map */ Set> keys(); @@ -226,9 +225,9 @@ public boolean equals(Object obj) { * * @param 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 + * @return value associated to the given key */ - V get(@Nonnull Key key); + Optional get(@Nonnull Key key); /** * Returns the value associated to the given key, or the given default value if none. @@ -238,7 +237,8 @@ public boolean equals(Object obj) { * @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 getOrDefault(@Nonnull Key key, V defaultValue); + @Nullable + V getOrDefault(@Nonnull Key key, @Nullable V defaultValue); /** * Returns {@code true} if given flag is {@code true}. @@ -248,13 +248,15 @@ public boolean equals(Object obj) { * @return whether the value associated to the given key is non-null and true */ default boolean checkFlag(@Nonnull Key flag) { - return Boolean.TRUE.equals(get(flag)); + return getOrDefault(flag, Boolean.FALSE); } /** - * {@return an immutable "map view" of all the properties}. + * Returns an immutable "map view" of all the properties. * This method is provided for compatibility with API working with {@link String}. * The type-safe method expecting {@link Key} arguments should be preferred. + * + * @return an immutable "map view" of all the properties */ @Nonnull Map asMap(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java index b432ea14a888..744ea6c78184 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java @@ -33,7 +33,7 @@ * or another kind of path. This class is like an enumeration, except that it is extensible: * plugins can define their own kinds of path. * - *

One path type is handled in a special way: contrarily to other options, + *

One path type is handled in a special way: unlike 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.

@@ -53,13 +53,13 @@ public final class JavaPathType extends PathType { * *

Context-sensitive interpretation

* 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: + * There are two circumstances where the dependency may nevertheless be placed somewhere else: * *
    *
  • 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).
  • - *
  • If a {@link #patchModule(String)} is also set and the main JAR file was placed on the module-path, + *
  • If a {@link #patchModule(String)} is also set and the main JAR file is placed on the module-path, * then the test dependency will be placed on the Java {@code --patch-module} option instead of the * class-path.
  • *
@@ -72,17 +72,17 @@ public final class JavaPathType extends PathType { * *

Context-sensitive interpretation

* 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: + * There are two circumstances where the dependency may nevertheless be placed somewhere else: * *
    *
  • If {@link #CLASSES} path type is also set, then the dependency should be placed on the - * module-path, but is nevertheless compatible with placement on the class-path. Compatibility can + * module-path, but is also 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.
  • - *
  • If a {@link #patchModule(String)} is also set and the main JAR file was placed on the module-path, + *
  • If a {@link #patchModule(String)} is also set and the main JAR file is placed on the module-path, * then the test dependency will be placed on the Java {@code --patch-module} option instead of the - * module-path.
  • + * {@code --module-path} option. *
*/ public static final JavaPathType MODULES = new JavaPathType("MODULES", "--module-path", null); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java index 6b3f7c15afb4..d34b84435844 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java @@ -137,6 +137,7 @@ public interface Type { * * @deprecated A value of {@code true} does not mean that the dependency should * be placed on the classpath. See {@link JavaPathType} instead for better analysis. + * This method will be removed before 4.0.0 GA. */ @Deprecated default boolean isAddedToClassPath() { diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java index 091431397ac2..4dac407def63 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java @@ -41,10 +41,12 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest { ResolutionScope getResolutionScope(); /** - * {@return a filter for the types of path (class-path, module-path, …) accepted by the tool}. + * Returns a filter for the types of path (class-path, module-path, …) accepted by the tool. * For example, if a Java tools accepts only class-path elements, then the filter should return * {@code true} for {@link JavaPathType#CLASSES} and {@code false} for {@link JavaPathType#MODULES}. * If no filter is explicitly set, then the default is a filter accepting everything. + * + * @return a filter for the types of path (class-path, module-path, …) accepted by the tool */ Predicate getPathTypeFilter(); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java index 45325d881545..929995c1c9ae 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java @@ -62,7 +62,9 @@ public DefaultDependency( DefaultDependencyProperties.Builder builder = new DefaultDependencyProperties.Builder(); for (Map.Entry entry : dependency.getArtifact().getProperties().entrySet()) { - DependencyProperties.Key key = DependencyProperties.Key.forName(entry.getKey(), String.class); + String name = entry.getKey(); + DependencyProperties.Key key = DependencyProperties.Key.forName(name) + .orElseGet(() -> new DependencyProperties.Key<>(name, String.class)); Function vc = VALUE_CONVERTERS.get(key.valueType()); if (vc != null) { builder.checkAndSet(key, vc.apply(entry.getValue())); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java index 966cbf8cff4e..3bf4ad266ef8 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java @@ -21,6 +21,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.Set; import org.apache.maven.api.DependencyProperties; @@ -115,13 +116,15 @@ public Builder setFlag(@Nonnull Key key) { * @throws IllegalStateException if the dependency properties have already been built */ public Builder setAll(@Nonnull DependencyProperties source) { - source.keys().forEach((key) -> checkAndSet(key, source.get(key))); + source.keys().forEach((key) -> source.get(key).ifPresent((value) -> checkAndSet(key, value))); return this; } /** - * {@return the dependency properties with the values previously set}. + * Returns the dependency properties with the values previously set. * This method can be invoked only once. + * + * @return the dependency properties with the values previously set */ @Nonnull public DefaultDependencyProperties build() { @@ -166,7 +169,7 @@ public DefaultDependencyProperties(@Nonnull Key... flags) { */ @Deprecated private void addCompatibility() { - PathType[] types = get(PATH_TYPES); + PathType[] types = get(PATH_TYPES).orElse(null); if (types != null) { boolean found = false; for (PathType type : types) { @@ -182,7 +185,9 @@ private void addCompatibility() { } /** - * {@return the keys of all properties in this map}. + * Returns the keys of all properties in this map. + * + * @return the keys of all properties in this map */ @Override public Set> keys() { @@ -194,11 +199,11 @@ public Set> keys() { * * @param 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 + * @return value associated to the given key */ @Override - public V get(Key key) { - return key.valueType().cast(properties.get(key)); + public Optional get(Key key) { + return Optional.ofNullable(key.valueType().cast(properties.get(key))); } /** @@ -217,8 +222,10 @@ public V getOrDefault(Key key, V defaultValue) { private transient Map mapView; /** - * {@return an immutable "map view" of all the properties}. + * Returns an immutable "map view" of all the properties. * This is computed when first needed + * + * @return an immutable "map view" of all the properties */ @Nonnull @Override @@ -235,7 +242,9 @@ public synchronized Map asMap() { } /** - * {@return a string representation of the key-value mapping}. + * Returns a string representation of the key-value mapping. + * + * @return a string representation of the key-value mapping */ @Override public String toString() { diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java index e45d624c7f64..4a639c5a8c14 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java @@ -228,7 +228,8 @@ void addDependency( * been added on the module-type. */ final DependencyProperties properties = dep.getDependencyProperties(); - final PathType[] pathTypes = properties.get(DependencyProperties.PATH_TYPES); + final PathType[] pathTypes = + properties.get(DependencyProperties.PATH_TYPES).orElse(null); if (containsPatches(pathTypes)) { if (outputModules == null) { // For telling users that it is too late for setting the output directory. diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java index c71d784bf6dc..53926b20a2d6 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java @@ -64,12 +64,12 @@ public DefaultType(String id, String language, String extension, String classifi @Override public String getId() { - return dependencyProperties.get(DependencyProperties.TYPE); + return dependencyProperties.get(DependencyProperties.TYPE).orElse(null); } @Override public String getLanguage() { - return dependencyProperties.get(DependencyProperties.LANGUAGE); + return dependencyProperties.get(DependencyProperties.LANGUAGE).orElse(null); } @Override From ab8782fc9e40a240ad4b0850d8184e08cc4de837 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sat, 20 Jan 2024 14:42:59 +0100 Subject: [PATCH 08/31] Remove the deprecated `FLAG_CLASS_PATH_CONSTITUENT` key and the `Type.isAddedToClassPath()` method. --- .../maven/api/DependencyProperties.java | 8 ------- .../main/java/org/apache/maven/api/Type.java | 16 ------------- .../DefaultArtifactHandlerManager.java | 13 +++++++++- .../impl/DefaultDependencyProperties.java | 24 ------------------- .../internal/impl/DefaultTypeRegistry.java | 3 ++- .../impl/types/EjbClientTypeProvider.java | 10 ++------ .../internal/impl/types/EjbTypeProvider.java | 10 ++------ 7 files changed, 18 insertions(+), 66 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java index 56fbacbe3071..19442feb6058 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java @@ -205,14 +205,6 @@ public boolean equals(Object obj) { */ Key FLAG_INCLUDES_DEPENDENCIES = new Key<>("includesDependencies", Boolean.class).intern(); - /** - * Boolean flag telling that dependency is meant to be placed on class path. - * - * @deprecated Use {@link #PATH_TYPES} and {@link JavaPathType#CLASSES} instead. - */ - @Deprecated - Key FLAG_CLASS_PATH_CONSTITUENT = new Key<>("classPathConstituent", Boolean.class).intern(); - /** * Returns the keys of all properties in this map. * diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java index d34b84435844..88ce25fd81b3 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java @@ -128,22 +128,6 @@ public interface Type { @Nullable String getClassifier(); - /** - * Specifies if the artifact contains java classes and can be added to the classpath. - * Whether the artifact should be added to the classpath depends on other - * {@linkplain #getDependencyProperties() dependency properties}. - * - * @return if the artifact can be added to the class path - * - * @deprecated A value of {@code true} does not mean that the dependency should - * be placed on the classpath. See {@link JavaPathType} instead for better analysis. - * This method will be removed before 4.0.0 GA. - */ - @Deprecated - default boolean isAddedToClassPath() { - return getDependencyProperties().checkFlag(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT); - } - /** * Specifies if the artifact already embeds its own dependencies. * This is the case for JEE packages or similar artifacts such as diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java index f873d817089c..14e5b46b5c9c 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java @@ -26,6 +26,9 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.PathType; import org.apache.maven.api.Type; import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.artifact.handler.ArtifactHandler; @@ -64,6 +67,14 @@ public void onEvent(Object event) { public ArtifactHandler getArtifactHandler(String id) { return allHandlers.computeIfAbsent(id, k -> { Type type = typeRegistry.getType(id); + boolean isAddedToClasspath = false; + for (PathType p : + type.getDependencyProperties().getOrDefault(DependencyProperties.PATH_TYPES, new PathType[0])) { + if (JavaPathType.CLASSES.equals(p)) { + isAddedToClasspath = true; + break; + } + } return new DefaultArtifactHandler( id, type.getExtension(), @@ -72,7 +83,7 @@ public ArtifactHandler getArtifactHandler(String id) { null, type.isIncludesDependencies(), type.getLanguage(), - type.isAddedToClassPath()); // TODO: watch out for module path + isAddedToClasspath); // TODO: watch out for module path }); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java index 3bf4ad266ef8..da1cc9d416ef 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java @@ -25,8 +25,6 @@ import java.util.Set; import org.apache.maven.api.DependencyProperties; -import org.apache.maven.api.JavaPathType; -import org.apache.maven.api.PathType; import org.apache.maven.api.annotations.Nonnull; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -146,7 +144,6 @@ public DefaultDependencyProperties build() { */ protected DefaultDependencyProperties(@Nonnull final Map, Object> properties) { this.properties = nonNull(properties, "properties"); - addCompatibility(); } /** @@ -161,27 +158,6 @@ public DefaultDependencyProperties(@Nonnull Key... flags) { for (Key flag : flags) { properties.put(flag, Boolean.TRUE); } - addCompatibility(); - } - - /** - * @deprecated Bridge with deprecated flag. To be removed if deprecated flag is removed. - */ - @Deprecated - private void addCompatibility() { - PathType[] types = get(PATH_TYPES).orElse(null); - if (types != null) { - boolean found = false; - for (PathType type : types) { - if (type.equals(JavaPathType.CLASSES)) { - found = true; - break; - } - } - properties.put(FLAG_CLASS_PATH_CONSTITUENT, found); - } else if (checkFlag(FLAG_CLASS_PATH_CONSTITUENT)) { - properties.put(PATH_TYPES, new PathType[] {JavaPathType.CLASSES}); - } } /** diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java index a7ebb5126275..d9d80c366025 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java @@ -26,6 +26,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Type; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.services.TypeRegistry; @@ -79,7 +80,7 @@ public Type getType(String id) { ArtifactHandler handler = manager.getArtifactHandler(id); DefaultDependencyProperties.Builder flags = new DefaultDependencyProperties.Builder(); if (handler.isAddedToClasspath()) { - flags.setFlag(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT); + flags.set(DependencyProperties.PATH_TYPES, new JavaPathType[] {JavaPathType.CLASSES}); } if (handler.isIncludesDependencies()) { flags.setFlag(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java index efbfe05a1cc0..b27c02afeaeb 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java @@ -22,9 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EjbClientTypeProvider.NAME) @@ -35,12 +34,7 @@ public class EjbClientTypeProvider implements Provider { private final Type type; public EjbClientTypeProvider() { - this.type = new DefaultType( - NAME, - Type.LANGUAGE_JAVA, - "jar", - "client", - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Type.LANGUAGE_JAVA, "jar", "client", JavaPathType.CLASSES); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java index e6f8fbdb4b5e..1da3543972ae 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java @@ -22,9 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EjbTypeProvider.NAME) @@ -35,12 +34,7 @@ public class EjbTypeProvider implements Provider { private final Type type; public EjbTypeProvider() { - this.type = new DefaultType( - NAME, - Type.LANGUAGE_JAVA, - "jar", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Type.LANGUAGE_JAVA, "jar", null, JavaPathType.CLASSES); } @Override From 3ae371a0e1f5de540b64c34d187bdeb08bba7314 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sat, 20 Jan 2024 17:05:19 +0100 Subject: [PATCH 09/31] Makes `PathType` an interface, `JavaPathType` an enumeration implementing that interface, and the case of the `--patch-module` option an inner class named `Modular` also implementing the `PathType` interface. The latter class generalizes `--path-module` support to other kinds of module-dependent option if some appear in the future. --- .../org/apache/maven/api/JavaPathType.java | 249 +++++++++++------- .../java/org/apache/maven/api/PathType.java | 94 ++----- .../impl/DefaultDependencyResolverResult.java | 7 +- 3 files changed, 175 insertions(+), 175 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java index 744ea6c78184..c9556f81645d 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java @@ -30,8 +30,7 @@ /** * 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. + * or another kind of path. * *

One path type is handled in a special way: unlike other options, * the paths specified in a {@code --patch-module} Java option is effective only for a specified module. @@ -46,7 +45,7 @@ * @since 4.0.0 */ @Experimental -public final class JavaPathType extends PathType { +public enum JavaPathType implements PathType { /** * The path identified by the Java {@code --class-path} option. * Used for compilation, execution and Javadoc among others. @@ -64,7 +63,7 @@ public final class JavaPathType extends PathType { * class-path. * */ - public static final JavaPathType CLASSES = new JavaPathType("CLASSES", "--class-path", null); + CLASSES("--class-path"), /** * The path identified by the Java {@code --module-path} option. @@ -85,13 +84,12 @@ public final class JavaPathType extends PathType { * {@code --module-path} option. * */ - public static final JavaPathType MODULES = new JavaPathType("MODULES", "--module-path", null); + MODULES("--module-path"), /** * The path identified by the Java {@code --upgrade-module-path} option. */ - public static final JavaPathType UPGRADE_MODULES = - new JavaPathType("UPGRADE_MODULES", "--upgrade-module-path", null); + UPGRADE_MODULES("--upgrade-module-path"), /** * The path identified by the Java {@code --patch-module} option. @@ -100,41 +98,32 @@ public final class JavaPathType extends PathType { * * @see #patchModule(String) */ - public static final JavaPathType PATCH_MODULE = new JavaPathType("PATCH_MODULE", "--patch-module", null); + PATCH_MODULE("--patch-module"), /** * The path identified by the Java {@code --processor-path} option. */ - public static final JavaPathType PROCESSOR_CLASSES = - new JavaPathType("PROCESSOR_CLASSES", "--processor-path", null); + PROCESSOR_CLASSES("--processor-path"), /** * The path identified by the Java {@code --processor-module-path} option. */ - public static final JavaPathType PROCESSOR_MODULES = - new JavaPathType("PROCESSOR_MODULES", "--processor-module-path", null); + PROCESSOR_MODULES("--processor-module-path"), /** * The path identified by the Java {@code -agentpath} option. */ - public static final JavaPathType AGENT = new JavaPathType("AGENT", "-agentpath", null); + AGENT("-agentpath"), /** * The path identified by the Javadoc {@code -doclet} option. */ - public static final JavaPathType DOCLET = new JavaPathType("DOCLET", "-doclet", null); + DOCLET("-doclet"), /** * The path identified by the Javadoc {@code -tagletpath} option. */ - public static final JavaPathType TAGLETS = new JavaPathType("TAGLETS", "-tagletpath", null); - - /** - * All predefined enumeration values. - */ - private static final JavaPathType[] VALUES = { - CLASSES, MODULES, UPGRADE_MODULES, PROCESSOR_CLASSES, PROCESSOR_MODULES, AGENT, DOCLET, TAGLETS - }; + TAGLETS("-tagletpath"); /** * Creates a path identified by the Java {@code --patch-module} option. @@ -149,88 +138,46 @@ public final class JavaPathType extends PathType { * @param moduleName name of the module on which to apply the path * @return an identification of the patch-module path for the given module. * - * @see #moduleName() - * @see #toString() + * @see Modular#moduleName() */ @Nonnull - public static JavaPathType patchModule(final String moduleName) { - return new JavaPathType("patchModule", "--patch-module", Objects.requireNonNull(moduleName)); + public static Modular patchModule(@Nonnull String moduleName) { + return PATCH_MODULE.new Modular(moduleName); } /** - * Creates a path for the specified option. If the {@code option} argument is one of the options - * associated to above-listed enumeration values, then that value is returned. Otherwise, this - * method returns a new {@code JavaPathType} instance for the given option. + * The tools option for this path, or {@code null} if none. * - * @param name the programmatic name of the new path type - * @param option the option associated to the path type, or {@code null} if none - * @return path type for the given option - */ - @Nonnull - public static JavaPathType forOption(final String name, final String option) { - for (final JavaPathType value : VALUES) { - if (value.option.equals(option)) { - return value; - } - } - return new JavaPathType(name, option, null); - } - - /** - * Name of the module to patch, or {@code null} if this path type is not for the {@code --patch-module} option. + * @see #option() */ - private final String moduleName; + private final String option; /** * Creates a new enumeration value for a path associated to the given tool option. * - * @param name the programmatic name of this path type * @param option the Java tools option for this path, or {@code null} if none - * @param moduleName name of the module to patch, or {@code null} if none */ - private JavaPathType(final String name, final String option, final String moduleName) { - super(name, option); - this.moduleName = moduleName; + JavaPathType(String option) { + this.option = option; } /** - * Returns the name of the module on which this option applies. - * This is present only for instances created by {@link #patchModule(String)}. + * Returns the name of the tool option for this path. For example, if this path type + * is {@link #MODULES}, then this method returns {@code "--module-path"}. The option + * does not include the {@linkplain Modular#moduleName() module name} on which it applies. * - * @return name of the module on which this option applies - */ - @Nonnull - public Optional moduleName() { - return Optional.ofNullable(moduleName); - } - - /** - * Returns the programmatic name of this path type, including the class name and module to patch if any. - * For example, if this type is {@link #MODULES}, then this method returns {@code JavaPathType.MODULES}. - * If this type was created by {@code patchModule("foo.bar")}, then this method returns - * {@code JavaPathType.patchModule("foo.bar")}. - * - * @return the programmatic name together with the module name on which it applies - * - * @see #name() - * @see #moduleName() + * @return the name of the tool option for this path type */ @Nonnull @Override - public String toString() { - String s = super.toString(); - if (moduleName != null) { - s = s + "(\"" + moduleName + "\")"; - } - return s; + public Optional option() { + return Optional.ofNullable(option); } /** - * Returns the option followed by a string representation of the given path elements. For example, - * if this type is {@link #MODULES}, then the option is {@code "--module-path"}. But if this type is - * {@code patchModule("foo.bar")}, then the option is {@code "--patch-module foo.bar"}. The option is followed - * by the given path elements, separated by the {@linkplain File#separatorChar platform-specific separator}. - * If the given {@code paths} argument contains no element, then this method returns an empty string. + * Returns the option followed by a string representation of the given path elements. + * For example, if this type is {@link #MODULES}, then the option is {@code "--module-path"} + * followed by the specified path elements. * * @param paths the path to format as a tool option * @return the option associated to this path type followed by the given path elements, @@ -240,6 +187,13 @@ public String toString() { @Nonnull @Override public String option(final Iterable paths) { + return format(null, paths); + } + + /** + * Implementation shared with {@link Modular}. + */ + final String format(final String moduleName, final Iterable paths) { if (option == null) { throw new IllegalStateException("No option is associated to this path type."); } @@ -253,30 +207,123 @@ public String option(final Iterable paths) { } /** - * Returns a hash code value for this type. + * Type of a path which is applied to only one specific Java module. + * The main case is the Java {@code --patch-module} option. * - * @return a hash code value + * @see #PATCH_MODULE + * @see #patchModule(String) */ - @Override - public int hashCode() { - return super.hashCode() + 37 * Objects.hashCode(moduleName); - } + public final class Modular implements PathType { + /** + * Name of the module for which a path is specified. + */ + @Nonnull + private final String moduleName; - /** - * Compares this type with the given object for equality. - * - * @param obj the object to compare with this type - * @return whether the two objects are equal - */ - @Override - public boolean equals(final Object obj) { - if (obj == this) { - return true; + /** + * Creates a new path type for the specified module. + * + * @param moduleName name of the module for which a path is specified + */ + private Modular(@Nonnull String moduleName) { + this.moduleName = Objects.requireNonNull(moduleName); + } + + /** + * Returns the type of path without indication about the target module. + * This is usually {@link #PATCH_MODULE}. + * + * @return type of path without indication about the target module + */ + @Nonnull + public JavaPathType rawType() { + return JavaPathType.this; + } + + /** + * Returns the name of the tool option for this path, not including the module name. + * + * @return name of the tool option for this path, not including the module name + */ + @Nonnull + @Override + public String name() { + return JavaPathType.this.name(); + } + + /** + * Returns the name of the module for which a path is specified + * + * @return name of the module for which a path is specified + */ + @Nonnull + public String moduleName() { + return moduleName; + } + + /** + * Returns the name of the tool option for this path. + * The option does not include the {@linkplain #moduleName() module name} on which it applies. + * + * @return the name of the tool option for this path type + */ + @Nonnull + @Override + public Optional option() { + return JavaPathType.this.option(); } - if (super.equals(obj)) { - final JavaPathType other = (JavaPathType) obj; - return Objects.equals(moduleName, other.moduleName); + + /** + * Returns the option followed by a string representation of the given path elements. + * The path elements are separated by an option-specific or platform-specific separator. + * If the given {@code paths} argument contains no element, then this method returns an empty string. + * + * @param paths the path to format as a string + * @return the option associated to this path type followed by the given path elements, + * or an empty string if there is no path element. + */ + @Nonnull + @Override + public String option(Iterable paths) { + return format(moduleName, paths); + } + + /** + * Returns the programmatic name of this path type, including the module to patch. + * For example, if this type was created by {@code JavaPathType.patchModule("foo.bar")}, + * then this method returns {@code "PATCH_MODULE:foo.bar")}. + * + * @return the programmatic name together with the module name on which it applies + */ + @Nonnull + @Override + public String toString() { + return name() + ':' + moduleName; + } + + /** + * Returns a hash code value for this type. + * + * @return a hash code value + */ + @Override + public int hashCode() { + return JavaPathType.this.hashCode() + 37 * moduleName.hashCode(); + } + + /** + * Compares this type with the given object for equality. + * + * @param obj the object to compare with this type + * @return whether the two objects are equal + */ + @Override + public boolean equals(final Object obj) { + if (obj instanceof Modular) { + Modular other = (Modular) obj; + return rawType().equals(other.rawType()) && moduleName.equals(other.moduleName); + } + return false; } - return false; } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java index 27dd04de7a13..b6d69f303759 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java @@ -19,7 +19,6 @@ 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; @@ -29,11 +28,8 @@ * 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. - * - *

Path types are often exclusive. For example, a dependency should not be both - * on the Java class-path and on the Java module-path.

+ * Path types are often exclusive. For example, a dependency should not be + * both on the Java class-path and on the Java module-path. * * @see DependencyProperties#PATH_TYPES * @see org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths() @@ -41,31 +37,7 @@ * @since 4.0.0 */ @Experimental -public abstract class PathType { - /** - * The programmatic name of this path type. - */ - @Nonnull - private final String name; - - /** - * The tools option for this path, or {@code null} if none. - * - * @see #option() - */ - final String option; - - /** - * Creates a new enumeration value for a path associated to the given tool option. - * - * @param name the programmatic name of this path type - * @param option the tool option for this path, or {@code null} if none - */ - protected PathType(final String name, final String option) { - this.name = Objects.requireNonNull(name); - this.option = option; - } - +public interface PathType { /** * Returns the programmatic name of this path type. For example, if this path type * is {@link JavaPathType#MODULES}, then this method returns {@code "MODULES"}. @@ -75,69 +47,51 @@ protected PathType(final String name, final String option) { * @see #toString() */ @Nonnull - public String name() { - return name; - } + String name(); /** * Returns the name of the tool option for this path. For example, if this path type * is {@link JavaPathType#MODULES}, then this method returns {@code "--module-path"}. - * The option does not include the {@linkplain JavaPathType#moduleName() module name} + * The option does not include the {@linkplain JavaPathType.Modular#moduleName() module name} * on which it applies. * * @return the name of the tool option for this path type */ @Nonnull - public Optional option() { - return Optional.ofNullable(option); - } + Optional option(); /** * Returns the option followed by a string representation of the given path elements. * The path elements are separated by an option-specific or platform-specific separator. * If the given {@code paths} argument contains no element, then this method returns an empty string. * + *

Examples

+ * If {@code paths} is a list containing two elements, {@code path1} and {@code path2}, then: + * + *
    + *
  • If this type is {@link JavaPathType#MODULES}, then this method returns + * {@code "--module-path path1:path2"} on Unix or {@code "--module-path path1;path2"} on Windows.
  • + *
  • If this type was created by {@code JavaPathType.patchModule("foo.bar")}, then the method returns + * {@code "--patch-module foo.bar=path1:path2"} on Unix or {@code "--patch-module foo.bar=path1;path2"} + * on Windows.
  • + *
+ * * @param paths the path to format as a string * @return the option associated to this path type followed by the given path elements, * or an empty string if there is no path element. */ @Nonnull - public abstract String option(Iterable paths); + String option(Iterable paths); /** - * Returns the programmatic name of this path type, including the class name. For example, - * if this type is {@link JavaPathType#MODULES}, then this method returns {@code "JavaPathType.MODULES"}. + * Returns the programmatic name of this path type, including the module to patch if any. + * For example, if this type is {@link JavaPathType#MODULES}, then this method returns {@code "MODULES"}. + * But if this type was created by {@code JavaPathType.patchModule("foo.bar")}, then this method returns + * {@code "PATCH_MODULE:foo.bar")}. * - * @return the programmatic name of this path type + * @return the programmatic name together with the module name on which it applies */ @Nonnull @Override - public String toString() { - return getClass().getSimpleName() + '.' + name; - } - - /** - * Returns a hash code value for this type. - * - * @return a hash code value - */ - @Override - public int hashCode() { - return getClass().hashCode() + name.hashCode() + 31 * Objects.hashCode(option); - } - - /** - * Compares this type with the given object for equality. - * - * @param obj the object to compare with this type - * @return whether the two objects are equal - */ - @Override - public boolean equals(final Object obj) { - if (obj != null && obj.getClass() == getClass()) { - final PathType other = (PathType) obj; - return name.equals(other.name) && Objects.equals(option, other.option); - } - return false; - } + String toString(); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java index 4a639c5a8c14..57c13aaceae9 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java @@ -280,11 +280,10 @@ void addDependency( private boolean containsPatches(final PathType[] types) { if (types != null) { for (PathType type : types) { - if (JavaPathType.PATCH_MODULE.equals(type)) { - return true; + if (type instanceof JavaPathType.Modular) { + type = ((JavaPathType.Modular) type).rawType(); } - if (type instanceof JavaPathType - && ((JavaPathType) type).moduleName().isPresent()) { + if (JavaPathType.PATCH_MODULE.equals(type)) { return true; } } From 67bd4b914f4e59c3e4de8c1bd5fe12d0110df1d7 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sun, 21 Jan 2024 16:19:34 +0100 Subject: [PATCH 10/31] Replace `PathType[]` by `Set` for the property value of `DependencyProperties.PATH_TYPES`. --- .../maven/api/DependencyProperties.java | 21 ++++++++++++++++-- .../DefaultArtifactHandlerManager.java | 13 +++-------- .../internal/impl/DefaultDependency.java | 8 ++++++- .../impl/DefaultDependencyProperties.java | 22 +++++++++++++++++++ .../impl/DefaultDependencyResolverResult.java | 22 +++++++++---------- .../maven/internal/impl/DefaultType.java | 2 +- .../internal/impl/DefaultTypeRegistry.java | 3 ++- .../impl/PathModularizationCache.java | 10 ++++----- 8 files changed, 68 insertions(+), 33 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java index 19442feb6058..3635072f024a 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java @@ -18,6 +18,7 @@ */ package org.apache.maven.api; +import java.util.Collections; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -196,7 +197,8 @@ public boolean equals(Object obj) { * case, the plugin may apply rules for choosing a path. See for example * {@link JavaPathType#CLASSES} and {@link JavaPathType#MODULES}.

*/ - Key PATH_TYPES = new Key<>("pathTypes", PathType[].class).intern(); + @SuppressWarnings("unchecked") + Key> PATH_TYPES = (Key) new Key<>("pathTypes", Set.class).intern(); /** * Boolean flag telling that dependency contains all of its dependencies. @@ -230,7 +232,9 @@ public boolean equals(Object obj) { * @return value associated to the given key, or {@code null} if none and the default is null */ @Nullable - V getOrDefault(@Nonnull Key key, @Nullable V defaultValue); + default V getOrDefault(@Nonnull Key key, @Nullable V defaultValue) { + return get(key).orElse(defaultValue); + } /** * Returns {@code true} if given flag is {@code true}. @@ -243,6 +247,19 @@ default boolean checkFlag(@Nonnull Key flag) { return getOrDefault(flag, Boolean.FALSE); } + /** + * Returns {@code true} if the set associated to the given key contains the specified element. + * An absence of set is interpreted as an empty set, which results in {@code false}. + * + * @param type of elements contained in the set + * @param flag the property to check + * @param value value to check in the set identified by the flag + * @return {@code true} if a set is associated to the given key and contains the given value + */ + default boolean checkContains(@Nonnull Key> flag, E value) { + return getOrDefault(flag, Collections.emptySet()).contains(value); + } + /** * Returns an immutable "map view" of all the properties. * This method is provided for compatibility with API working with {@link String}. diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java index 14e5b46b5c9c..bb71f70fce6e 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java @@ -28,7 +28,6 @@ import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.JavaPathType; -import org.apache.maven.api.PathType; import org.apache.maven.api.Type; import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.artifact.handler.ArtifactHandler; @@ -67,14 +66,6 @@ public void onEvent(Object event) { public ArtifactHandler getArtifactHandler(String id) { return allHandlers.computeIfAbsent(id, k -> { Type type = typeRegistry.getType(id); - boolean isAddedToClasspath = false; - for (PathType p : - type.getDependencyProperties().getOrDefault(DependencyProperties.PATH_TYPES, new PathType[0])) { - if (JavaPathType.CLASSES.equals(p)) { - isAddedToClasspath = true; - break; - } - } return new DefaultArtifactHandler( id, type.getExtension(), @@ -83,7 +74,9 @@ public ArtifactHandler getArtifactHandler(String id) { null, type.isIncludesDependencies(), type.getLanguage(), - isAddedToClasspath); // TODO: watch out for module path + type.getDependencyProperties() + .checkContains(DependencyProperties.PATH_TYPES, JavaPathType.CLASSES)); + // TODO: watch out for module path }); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java index 929995c1c9ae..ccabe02dcc25 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java @@ -43,11 +43,17 @@ public class DefaultDependency implements Dependency { * A mapping from {@link ArtifactProperties} values to {@link DependencyProperties} values. * Used for conversion from Eclipse model to Maven model of dependency properties. */ - private static final Map, Function> VALUE_CONVERTERS = new HashMap<>(4); + private static final Map, Function> VALUE_CONVERTERS = new HashMap<>(12); static { VALUE_CONVERTERS.put(String.class, String::valueOf); VALUE_CONVERTERS.put(Boolean.class, Boolean::valueOf); + VALUE_CONVERTERS.put(Byte.class, Byte::valueOf); + VALUE_CONVERTERS.put(Short.class, Short::valueOf); + VALUE_CONVERTERS.put(Integer.class, Integer::valueOf); + VALUE_CONVERTERS.put(Long.class, Long::valueOf); + VALUE_CONVERTERS.put(Float.class, Float::valueOf); + VALUE_CONVERTERS.put(Double.class, Double::valueOf); } private final InternalSession session; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java index da1cc9d416ef..083fdf947b5b 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java @@ -18,8 +18,10 @@ */ package org.apache.maven.internal.impl; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -82,6 +84,8 @@ public Builder set(@Nonnull Key key, @Nonnull V value) { /** * Checks the type of the given value, then associates to the given key. + * Note that if {@code } is a collection such as {@code Set}, + * then this method cannot verify that all elements are of the expected type. * * @param type of value to add * @param key key of the value to add @@ -90,10 +94,27 @@ public Builder set(@Nonnull Key key, @Nonnull V value) { * @throws ClassCastException if the given value is not of type {@code } * @throws IllegalStateException if the dependency properties have already been built */ + @Nonnull public Builder checkAndSet(@Nonnull Key key, @Nonnull Object value) { return set(key, key.valueType().cast(value)); } + /** + * Associates the given set of values to the given key. + * If a set was already defined for the given key, the new set replaces it. + * + * @param type of elements in the set + * @param key key of the set to add + * @param values the elements in the set + * @return {@code this} for method call chaining + * @throws IllegalStateException if the dependency properties have already been built + */ + @Nonnull + @SafeVarargs + public final Builder setElements(@Nonnull Key> key, @Nonnull E... values) { + return set(key, Collections.unmodifiableSet(new HashSet<>(Arrays.asList(values)))); + } + /** * Associates the value {@code Boolean.TRUE} to the given key. * @@ -113,6 +134,7 @@ public Builder setFlag(@Nonnull Key key) { * @return {@code this} for method call chaining * @throws IllegalStateException if the dependency properties have already been built */ + @Nonnull public Builder setAll(@Nonnull DependencyProperties source) { source.keys().forEach((key) -> source.get(key).ifPresent((value) -> checkAndSet(key, value))); return this; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java index 57c13aaceae9..8804fca33d7e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java @@ -228,8 +228,8 @@ void addDependency( * been added on the module-type. */ final DependencyProperties properties = dep.getDependencyProperties(); - final PathType[] pathTypes = - properties.get(DependencyProperties.PATH_TYPES).orElse(null); + final Set pathTypes = + properties.getOrDefault(DependencyProperties.PATH_TYPES, Collections.emptySet()); if (containsPatches(pathTypes)) { if (outputModules == null) { // For telling users that it is too late for setting the output directory. @@ -275,17 +275,15 @@ void addDependency( } /** - * Returns whether the given array of path types contains at least one patch for a module. + * Returns whether the given set of path types contains at least one patch for a module. */ - private boolean containsPatches(final PathType[] types) { - if (types != null) { - for (PathType type : types) { - if (type instanceof JavaPathType.Modular) { - type = ((JavaPathType.Modular) type).rawType(); - } - if (JavaPathType.PATCH_MODULE.equals(type)) { - return true; - } + private boolean containsPatches(final Set types) { + for (PathType type : types) { + if (type instanceof JavaPathType.Modular) { + type = ((JavaPathType.Modular) type).rawType(); + } + if (JavaPathType.PATCH_MODULE.equals(type)) { + return true; } } return false; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java index 53926b20a2d6..50e6ce15e675 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java @@ -58,7 +58,7 @@ public DefaultType(String id, String language, String extension, String classifi dependencyProperties = new DefaultDependencyProperties.Builder() .set(DependencyProperties.TYPE, id) .set(DependencyProperties.LANGUAGE, language) - .set(DependencyProperties.PATH_TYPES, pathTypes) + .setElements(DependencyProperties.PATH_TYPES, pathTypes) .build(); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java index d9d80c366025..e0e8f78252a6 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java @@ -22,6 +22,7 @@ import javax.inject.Named; import javax.inject.Singleton; +import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -80,7 +81,7 @@ public Type getType(String id) { ArtifactHandler handler = manager.getArtifactHandler(id); DefaultDependencyProperties.Builder flags = new DefaultDependencyProperties.Builder(); if (handler.isAddedToClasspath()) { - flags.set(DependencyProperties.PATH_TYPES, new JavaPathType[] {JavaPathType.CLASSES}); + flags.set(DependencyProperties.PATH_TYPES, Collections.singleton(JavaPathType.CLASSES)); } if (handler.isIncludesDependencies()) { flags.setFlag(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java index 937c3826db07..067d8c776beb 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; import org.apache.maven.api.JavaPathType; @@ -96,17 +97,14 @@ private PathType getPathType(final Path path) throws IOException { *

If the dependency can be a constituent of both the class-path and the module-path, * then the path type is determined by checking if the dependency is modular.

* - * @param types types of path where a dependency can be placed, or {@code null} if unspecified - * @param filter filter the paths accepted by the tool which will consume the path. + * @param types types of path where a dependency can be placed + * @param filter filter the paths accepted by the tool which will consume the path * @param path path to the JAR file or output directory of the dependency * @return where to place the dependency, or an empty value if the placement cannot be determined * @throws IOException if an error occurred while reading module information */ - Optional selectPathType(final PathType[] types, final Predicate filter, final Path path) + Optional selectPathType(final Set types, final Predicate filter, final Path path) throws IOException { - if (types == null) { - return Optional.empty(); - } PathType selected = null; boolean classes = false; boolean modules = false; From 3d55f24a88b349d4fa5189d35e3a5b279dca71e7 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sun, 21 Jan 2024 16:49:16 +0100 Subject: [PATCH 11/31] Replace HTML headings by paragraph and bold characters for avoiding compilation issues on Java 11. This commit may be reverted in the future if Java 17 become a minimal requirement for compilation. --- .../main/java/org/apache/maven/api/JavaPathType.java | 11 ++++++----- .../src/main/java/org/apache/maven/api/PathType.java | 4 ++-- .../maven/api/services/DependencyResolverResult.java | 4 ++-- .../internal/impl/DefaultDependencyProperties.java | 3 ++- .../maven/internal/impl/PathModularization.java | 3 ++- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java index c9556f81645d..578e02ac01eb 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java @@ -50,10 +50,10 @@ public enum JavaPathType implements PathType { * The path identified by the Java {@code --class-path} option. * Used for compilation, execution and Javadoc among others. * - *

Context-sensitive interpretation

+ *

Context-sensitive interpretation: * A dependency with this path type will not necessarily be placed on the class-path. * There are two circumstances where the dependency may nevertheless be placed somewhere else: - * + *

*
    *
  • 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, @@ -69,10 +69,10 @@ public enum JavaPathType implements PathType { * The path identified by the Java {@code --module-path} option. * Used for compilation, execution and Javadoc among others. * - *

    Context-sensitive interpretation

    + *

    Context-sensitive interpretation: * A dependency with this flag will not necessarily be placed on the module-path. * There are two circumstances where the dependency may nevertheless be placed somewhere else: - * + *

    *
      *
    • If {@link #CLASSES} path type is also set, then the dependency should be placed on the * module-path, but is also compatible with placement on the class-path. Compatibility can @@ -130,10 +130,11 @@ public enum JavaPathType implements PathType { * Contrarily to the other types of paths, this path is applied to only * one specific module. Used for compilation and execution among others. * - *

      Context-sensitive interpretation

      + *

      Context-sensitive interpretation: * This path type makes sense only when a main module is added on the module-path by another dependency. * In no main module is found, the patch dependency may be added on the class-path or module-path * depending on whether {@link #CLASSES} or {@link #MODULES} is present. + *

      * * @param moduleName name of the module on which to apply the path * @return an identification of the patch-module path for the given module. diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java index b6d69f303759..d862e9a92561 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java @@ -65,9 +65,9 @@ public interface PathType { * The path elements are separated by an option-specific or platform-specific separator. * If the given {@code paths} argument contains no element, then this method returns an empty string. * - *

      Examples

      + *

      Examples: * If {@code paths} is a list containing two elements, {@code path1} and {@code path2}, then: - * + *

      *
        *
      • If this type is {@link JavaPathType#MODULES}, then this method returns * {@code "--module-path path1:path2"} on Unix or {@code "--module-path path1;path2"} on Windows.
      • 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 9230207445c7..60468046145e 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 @@ -55,12 +55,12 @@ public interface DependencyResolverResult extends DependencyCollectorResult { * In the case of Java tools, the map may also contain {@code --patch-module} options, which are * {@linkplain org.apache.maven.api.JavaPathType#patchModule(String) handled in a special way}. * - *

        Design note

        + *

        Design note: * All types of path are determined together because they are sometime mutually exclusive. * For example, an artifact of type {@value org.apache.maven.api.Type#JAR} can be placed * either on the class-path or on the module-path. The project needs to make a choice * (possibly using heuristic rules), then to add the dependency in only one of the options - * identified by {@link PathType}. + * identified by {@link PathType}.

        * * @return file paths to place on the different tool options */ diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java index 083fdf947b5b..653d7f9e5b88 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java @@ -63,9 +63,10 @@ public Builder() { * Associates the given value to the given key. * If a value was already defined for the given key, the new value replaces it. * - *

        Implementation note

        + *

        Implementation note: * All setter methods in {@code Builder} ultimately delegate to this method. * This architecture provides a single point that subclasses can override. + *

        * * @param type of value to add * @param key key of the value to add diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java index 48436f33e857..631f8344c254 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java @@ -101,8 +101,9 @@ private PathModularization() { * be null instead of the actual module name. This option can avoid the cost of reading module * descriptors when only the modules existence needs to be verified.

        * - *

        Algorithm

        + *

        Algorithm: * If the given path is a directory, then there is a choice: + *

        *
          *
        • Package hierarchy: if a {@code module-info.class} file is found at the root, * then builds a singleton map with the module name declared in that descriptor.
        • From 943fb04fd095587f16017e551840060a9072fc42 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 24 Jan 2024 18:06:53 +0100 Subject: [PATCH 12/31] Step 2: Changes: * Properties moved to Artifacts from Dependencies * snapshot check delegated to Aether Artifact * new types for build path, build path scope, dependency scope, language * changes propagated --- .../java/org/apache/maven/api/Artifact.java | 8 + ...roperties.java => ArtifactProperties.java} | 10 +- .../java/org/apache/maven/api/BuildPath.java | 48 ++++++ .../org/apache/maven/api/BuildPathScope.java | 46 ++++++ .../java/org/apache/maven/api/Dependency.java | 8 - .../org/apache/maven/api/DependencyScope.java | 148 ++++++++++++++++++ .../java/org/apache/maven/api/Language.java | 105 +++++++++++++ .../java/org/apache/maven/api/Packaging.java | 43 +++++ .../java/org/apache/maven/api/Session.java | 3 + .../main/java/org/apache/maven/api/Type.java | 26 ++- .../maven/api/services/LanguageManager.java | 34 ++++ .../maven/api/services/VersionParser.java | 8 +- .../artifact/handler/ArtifactHandler.java | 4 + .../DefaultArtifactHandlerManager.java | 8 +- .../internal/aether/TypeRegistryAdapter.java | 2 +- .../maven/internal/impl/DefaultArtifact.java | 11 +- ...es.java => DefaultArtifactProperties.java} | 16 +- .../internal/impl/DefaultDependency.java | 26 ++- .../maven/internal/impl/DefaultType.java | 37 +++-- .../internal/impl/DefaultTypeRegistry.java | 17 +- .../impl/language/DefaultLanguageManager.java | 47 ++++++ .../internal/impl/types/BomTypeProvider.java | 5 +- .../internal/impl/types/EarTypeProvider.java | 9 +- .../impl/types/EjbClientTypeProvider.java | 9 +- .../internal/impl/types/EjbTypeProvider.java | 9 +- .../internal/impl/types/JarTypeProvider.java | 9 +- .../impl/types/JavaSourceTypeProvider.java | 5 +- .../impl/types/JavadocTypeProvider.java | 9 +- .../impl/types/MavenPluginTypeProvider.java | 9 +- .../internal/impl/types/ParTypeProvider.java | 9 +- .../internal/impl/types/PomTypeProvider.java | 5 +- .../internal/impl/types/RarTypeProvider.java | 9 +- .../impl/types/TestJarTypeProvider.java | 9 +- .../internal/impl/types/WarTypeProvider.java | 9 +- 34 files changed, 627 insertions(+), 133 deletions(-) rename api/maven-api-core/src/main/java/org/apache/maven/api/{DependencyProperties.java => ArtifactProperties.java} (82%) create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/Language.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageManager.java rename maven-core/src/main/java/org/apache/maven/internal/impl/{DefaultDependencyProperties.java => DefaultArtifactProperties.java} (78%) create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/language/DefaultLanguageManager.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java index bdc18b958c45..e92ffd732f1e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java @@ -105,6 +105,14 @@ default String key() { */ boolean isSnapshot(); + /** + * The artifact properties. + * + * @return the artifact properties, never {@code null} + */ + @Nonnull + ArtifactProperties getArtifactProperties(); + /** * Shortcut for {@code session.createArtifactCoordinate(artifact)} * diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactProperties.java similarity index 82% rename from api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java rename to api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactProperties.java index 9f634168480b..fc3c197ccc45 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactProperties.java @@ -25,13 +25,13 @@ import org.apache.maven.api.annotations.Nonnull; /** - * Dependency properties supported by Maven Core. + * Artifact properties supported by Maven Core. * * @since 4.0.0 */ @Experimental @Immutable -public interface DependencyProperties { +public interface ArtifactProperties { /** * 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. @@ -41,10 +41,12 @@ public interface DependencyProperties { String FLAG_INCLUDES_DEPENDENCIES = "includesDependencies"; /** - * Boolean flag telling that dependency is meant to be placed on class path. Value of this key should be parsed with + * Boolean flag telling that dependency is meant to be part of build path. Value of this key should be parsed with * {@link Boolean#parseBoolean(String)} to obtain value. + *

          + * Important: this flag must be kept in sync with resolver! (as is used during collection) */ - String FLAG_CLASS_PATH_CONSTITUENT = "classPathConstituent"; + String FLAG_BUILD_PATH_CONSTITUENT = "constitutesBuildPath"; /** * Returns immutable "map view" of all the properties. diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java new file mode 100644 index 000000000000..f370bde8b1a2 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java @@ -0,0 +1,48 @@ +/* + * 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.util.Collection; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Immutable; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Build path. Build path is calculated for given {@link Project} and {@link BuildPathScope}. + * + * @since 4.0.0 + */ +@Experimental +@Immutable +public interface BuildPath { + @Nonnull + Project project(); + + @Nonnull + BuildPathScope buildPathScope(); + + @Nonnull + default Language language() { + return buildPathScope().language(); + } + + @Nonnull + Collection getArtifacts(); +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java new file mode 100644 index 000000000000..c63ebd3968ac --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java @@ -0,0 +1,46 @@ +/* + * 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.util.Collection; + +import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Immutable; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Build path scope. + *

          + * Implementation must have {@code equals()} and {@code hashCode()} implemented, so implementations of this interface + * can be used as keys. + * + * @since 4.0.0 + */ +@Experimental +@Immutable +public interface BuildPathScope { + @Nonnull + String id(); + + @Nonnull + Language language(); + + @Nonnull + Collection getDependencyScopes(); +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java index efad1415adf8..888e247fe1cf 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java @@ -30,14 +30,6 @@ public interface Dependency extends Artifact { @Nonnull Type getType(); - /** - * The dependency properties. - * - * @return the dependency properties, never {@code null} - */ - @Nonnull - DependencyProperties getDependencyProperties(); - @Nonnull Scope getScope(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java new file mode 100644 index 000000000000..ab50e90f23de --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java @@ -0,0 +1,148 @@ +/* + * 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 org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Immutable; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Dependency scope. + *

          + * Implementation must have {@code equals()} and {@code hashCode()} implemented, so implementations of this interface + * can be used as keys. + * + * @since 4.0.0 + */ +@Experimental +@Immutable +public interface DependencyScope { + @Nonnull + String id(); + + boolean isTransitive(); + + DependencyScope NONE = new DependencyScope() { + @Override + public String id() { + return "none"; + } + + @Override + public boolean isTransitive() { + return false; + } + }; + + DependencyScope COMPILE_ONLY = new DependencyScope() { + @Override + public String id() { + return "compile-only"; + } + + @Override + public boolean isTransitive() { + return false; + } + }; + + DependencyScope COMPILE = new DependencyScope() { + @Override + public String id() { + return "compile"; + } + + @Override + public boolean isTransitive() { + return true; + } + }; + + DependencyScope RUNTIME = new DependencyScope() { + @Override + public String id() { + return "runtime"; + } + + @Override + public boolean isTransitive() { + return true; + } + }; + + DependencyScope PROVIDED = new DependencyScope() { + @Override + public String id() { + return "provided"; + } + + @Override + public boolean isTransitive() { + return false; + } + }; + + DependencyScope TEST_ONLY = new DependencyScope() { + @Override + public String id() { + return "test-only"; + } + + @Override + public boolean isTransitive() { + return false; + } + }; + + DependencyScope TEST = new DependencyScope() { + @Override + public String id() { + return "test"; + } + + @Override + public boolean isTransitive() { + return false; + } + }; + + DependencyScope TEST_RUNTIME = new DependencyScope() { + @Override + public String id() { + return "test-runtime"; + } + + @Override + public boolean isTransitive() { + return false; + } + }; + + DependencyScope SYSTEM = new DependencyScope() { + @Override + public String id() { + return "system"; + } + + @Override + public boolean isTransitive() { + return false; + } + }; +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java new file mode 100644 index 000000000000..700c53f0da86 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java @@ -0,0 +1,105 @@ +/* + * 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 org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Immutable; +import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; + +/** + * Language. + *

          + * Implementation must have {@code equals()} and {@code hashCode()} implemented, so implementations of this interface + * can be used as keys. + * + * @since 4.0.0 + */ +@Experimental +@Immutable +public interface Language { + /** + * The "none" language. It is not versioned, family is same to itself, and compatible with itself only. + * In turn, every {@link Language} implementation must be compatible with {@code NONE} language. + */ + Language NONE = new Language() { + @Override + public String id() { + return "none"; + } + + @Override + public Language family() { + return this; + } + + @Override + public Version version() { + return null; + } + + @Override + public boolean isCompatibleWith(Language language) { + return this == language; + } + }; + + Language JAVA_FAMILY = new Language() { + @Override + public String id() { + return "java"; + } + + @Override + public Language family() { + return this; + } + + @Override + public Version version() { + return null; + } + + public boolean isCompatibleWith(Language language) { + Language family = language.family(); + return this == family || NONE == family; + } + }; + + @Nonnull + String id(); + + @Nonnull + Language family(); + + @Nullable + Version version(); + + /** + * Returns {@code true} if this language is compatible with provided language. + * For example "Java 8" is compatible with "Java 11", but other way is not true. + *

          + * Important note: every implementation must return {@code true} if passed in language is {@link #NONE}. + *

          + * By default, every language is compatible with itself and {@link #NONE} language. Override if needed. + */ + default boolean isCompatibleWith(Language language) { + return this == language || NONE == language.family(); + } +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java new file mode 100644 index 000000000000..9327178c9802 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java @@ -0,0 +1,43 @@ +/* + * 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 org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Immutable; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Interface representing a Maven project packaging. + * + * @since 4.0.0 + */ +@Experimental +@Immutable +public interface Packaging { + @Nonnull + String id(); + + @Nonnull + default Language language() { + return getType().getLanguage(); + } + + @Nonnull + Type getType(); +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index 65d4798c7c6d..cd9dd024c7b7 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -385,6 +385,9 @@ Artifact createArtifact( * Checks whether a given artifact version is considered a {@code SNAPSHOT} or not. *

          * Shortcut for {@code getService(ArtifactManager.class).isSnapshot(...)}. + *

          + * In case there is {@link Artifact} in scope, the recommended way to perform this check is + * use of {@link Artifact#isSnapshot()} instead. * * @see org.apache.maven.api.services.VersionParser#isSnapshot(String) */ diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java index 15ffc0b59a69..473d9a661152 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java @@ -30,21 +30,17 @@ *

          * It provides information about the file type (or extension) of the associated artifact, * its default classifier, and how the artifact will be used in the build when creating - * classpaths. + * various build paths. *

          * For example, the type {@code java-source} has a {@code jar} extension and a * {@code sources} classifier. The artifact and its dependencies should be added - * to the classpath. + * to the build path. * * @since 4.0.0 */ @Experimental @Immutable public interface Type { - - String LANGUAGE_NONE = "none"; - String LANGUAGE_JAVA = "java"; - /** * Returns the dependency type id. * The id uniquely identifies this dependency type. @@ -59,7 +55,8 @@ public interface Type { * * @return the language of this type, never {@code null}. */ - String getLanguage(); + @Nonnull + Language getLanguage(); /** * Get the file extension of artifacts of this type. @@ -80,13 +77,12 @@ public interface Type { String getClassifier(); /** - * Specifies if the artifact contains java classes and should be - * added to the classpath. + * Specifies if the artifact should be added to the build path. * - * @return if the artifact should be added to the class path + * @return if the artifact should be added to the build path */ - default boolean isAddedToClassPath() { - return getDependencyProperties().checkFlag(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT); + default boolean isBuildPathConstituent() { + return getArtifactProperties().checkFlag(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT); } /** @@ -97,14 +93,14 @@ default boolean isAddedToClassPath() { * @return if the artifact's dependencies are included in the artifact */ default boolean isIncludesDependencies() { - return getDependencyProperties().checkFlag(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); + return getArtifactProperties().checkFlag(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES); } /** - * Gets the default properties associated with this dependency type. + * Gets the default properties associated with this type. * * @return the default properties, never {@code null}. */ @Nonnull - DependencyProperties getDependencyProperties(); + ArtifactProperties getArtifactProperties(); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageManager.java new file mode 100644 index 000000000000..c322407be744 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageManager.java @@ -0,0 +1,34 @@ +/* + * 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.services; + +import java.util.Optional; + +import org.apache.maven.api.Language; +import org.apache.maven.api.Service; +import org.apache.maven.api.annotations.Nonnull; + +public interface LanguageManager extends Service { + @Nonnull + Optional lookupLanguageFamily(String id); + + default Language requireLanguageFamily(String id) { + return lookupLanguageFamily(id).orElseThrow(() -> new IllegalArgumentException("Unknown language")); + } +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java index d344122d7f19..a4f8484df042 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java @@ -18,10 +18,7 @@ */ package org.apache.maven.api.services; -import org.apache.maven.api.Service; -import org.apache.maven.api.Version; -import org.apache.maven.api.VersionConstraint; -import org.apache.maven.api.VersionRange; +import org.apache.maven.api.*; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; @@ -66,6 +63,9 @@ public interface VersionParser extends Service { /** * Checks whether a given artifact version is considered a {@code SNAPSHOT} or not. + *

          + * In case there is {@link Artifact} in scope, the recommended way to perform this check is + * use of {@link Artifact#isSnapshot()} instead. */ boolean isSnapshot(@Nonnull String version); } diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java b/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java index 92cca2a069dd..364e12425ee8 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java @@ -53,5 +53,9 @@ public interface ArtifactHandler { String getLanguage(); + /** + * IMPORTANT: this is WRONGLY NAMED method (and/or remnant for Maven2). + * Its meaning is "is added to build path", that is used to create classpath/modulepath/etc. + */ boolean isAddedToClasspath(); } diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java index 87166eb29a75..f25856333bb6 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java @@ -70,9 +70,13 @@ public ArtifactHandler getArtifactHandler(String id) { null, null, type.isIncludesDependencies(), - type.getLanguage(), - type.isAddedToClassPath()); // TODO: watch out for module path + type.getLanguage().id(), + type.isBuildPathConstituent()); }); + + // Note: here, type decides is artifact added to "build path" (for example during resolution) + // and "build path" is intermediate data that is used to create actual Java classpath/modulepath + // but to create those, proper filtering should happen via Type properties. } public void addHandlers(Map handlers) { diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java index b5f3f9c61437..1d0dca3ee2d9 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java +++ b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java @@ -45,7 +45,7 @@ public ArtifactType get(String typeId) { type.getLanguage(), type.getExtension(), type.getClassifier(), - type.getDependencyProperties()); + type.getArtifactProperties()); } return null; } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java index 563797f05c49..35ca4439593c 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java @@ -22,9 +22,9 @@ import org.apache.maven.api.Artifact; import org.apache.maven.api.ArtifactCoordinate; +import org.apache.maven.api.ArtifactProperties; import org.apache.maven.api.Version; import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.repository.internal.DefaultModelVersionParser; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -34,11 +34,13 @@ public class DefaultArtifact implements Artifact { private final @Nonnull InternalSession session; private final @Nonnull org.eclipse.aether.artifact.Artifact artifact; + private final @Nonnull ArtifactProperties artifactProperties; private final String key; public DefaultArtifact(@Nonnull InternalSession session, @Nonnull org.eclipse.aether.artifact.Artifact artifact) { this.session = nonNull(session, "session"); this.artifact = nonNull(artifact, "artifact"); + this.artifactProperties = new DefaultArtifactProperties(artifact.getProperties()); this.key = getGroupId() + ':' + getArtifactId() @@ -95,7 +97,12 @@ public String getClassifier() { @Override public boolean isSnapshot() { - return DefaultModelVersionParser.checkSnapshot(artifact.getVersion()); + return artifact.isSnapshot(); + } + + @Override + public ArtifactProperties getArtifactProperties() { + return artifactProperties; } @Nonnull diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactProperties.java similarity index 78% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java rename to maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactProperties.java index 2ee780713034..f3329620c42c 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactProperties.java @@ -18,13 +18,9 @@ */ package org.apache.maven.internal.impl; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.*; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; import org.apache.maven.api.annotations.Nonnull; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -32,14 +28,14 @@ /** * Default implementation of artifact properties. */ -public class DefaultDependencyProperties implements DependencyProperties { +public class DefaultArtifactProperties implements ArtifactProperties { private final Map properties; - public DefaultDependencyProperties(String... flags) { + public DefaultArtifactProperties(String... flags) { this(Arrays.asList(flags)); } - public DefaultDependencyProperties(@Nonnull Collection flags) { + public DefaultArtifactProperties(@Nonnull Collection flags) { nonNull(flags, "flags"); HashMap map = new HashMap<>(); for (String flag : flags) { @@ -48,7 +44,7 @@ public DefaultDependencyProperties(@Nonnull Collection flags) { this.properties = Collections.unmodifiableMap(map); } - public DefaultDependencyProperties(@Nonnull Map properties) { + public DefaultArtifactProperties(@Nonnull Map properties) { this.properties = Collections.unmodifiableMap(nonNull(properties, "properties")); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java index 3f2f06893ebf..40381e965e24 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java @@ -20,33 +20,25 @@ import java.util.Objects; -import org.apache.maven.api.Artifact; -import org.apache.maven.api.Dependency; -import org.apache.maven.api.DependencyCoordinate; -import org.apache.maven.api.DependencyProperties; -import org.apache.maven.api.Scope; -import org.apache.maven.api.Type; -import org.apache.maven.api.Version; +import org.apache.maven.api.*; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.services.TypeRegistry; -import org.apache.maven.repository.internal.DefaultModelVersionParser; -import org.eclipse.aether.artifact.ArtifactProperties; import static org.apache.maven.internal.impl.Utils.nonNull; public class DefaultDependency implements Dependency { private final InternalSession session; private final org.eclipse.aether.graph.Dependency dependency; - private final DependencyProperties dependencyProperties; + private final ArtifactProperties artifactProperties; private final String key; public DefaultDependency( @Nonnull InternalSession session, @Nonnull org.eclipse.aether.graph.Dependency dependency) { this.session = nonNull(session, "session"); this.dependency = nonNull(dependency, "dependency"); - this.dependencyProperties = - new DefaultDependencyProperties(dependency.getArtifact().getProperties()); + this.artifactProperties = + new DefaultArtifactProperties(dependency.getArtifact().getProperties()); this.key = getGroupId() + ':' + getArtifactId() @@ -101,18 +93,20 @@ public String getExtension() { public Type getType() { String type = dependency .getArtifact() - .getProperty(ArtifactProperties.TYPE, dependency.getArtifact().getExtension()); + .getProperty( + org.eclipse.aether.artifact.ArtifactProperties.TYPE, + dependency.getArtifact().getExtension()); return session.getService(TypeRegistry.class).getType(type); } @Override - public DependencyProperties getDependencyProperties() { - return dependencyProperties; + public ArtifactProperties getArtifactProperties() { + return artifactProperties; } @Override public boolean isSnapshot() { - return DefaultModelVersionParser.checkSnapshot(dependency.getArtifact().getVersion()); + return dependency.getArtifact().isSnapshot(); } @Nonnull diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java index 6297f5c4dde0..4098cc9c058a 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java @@ -21,45 +21,44 @@ import java.util.HashMap; import java.util.Map; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.eclipse.aether.artifact.ArtifactProperties; import org.eclipse.aether.artifact.ArtifactType; import static org.apache.maven.internal.impl.Utils.nonNull; public class DefaultType implements Type, ArtifactType { + private final Language language; + private final String extension; private final String classifier; - private final DependencyProperties dependencyProperties; + private final ArtifactProperties artifactProperties; public DefaultType( - String id, - String language, - String extension, - String classifier, - DependencyProperties dependencyProperties) { + String id, Language language, String extension, String classifier, ArtifactProperties artifactProperties) { nonNull(id, "id"); nonNull(language, "language"); + this.language = language; this.extension = nonNull(extension, "extension"); this.classifier = classifier; - nonNull(dependencyProperties, "dependencyProperties"); - HashMap props = new HashMap<>(dependencyProperties.asMap()); - props.put(ArtifactProperties.TYPE, id); - props.put(ArtifactProperties.LANGUAGE, language); - this.dependencyProperties = new DefaultDependencyProperties(props); + nonNull(artifactProperties, "artifactProperties"); + HashMap props = new HashMap<>(artifactProperties.asMap()); + props.put(org.eclipse.aether.artifact.ArtifactProperties.TYPE, id); + props.put(org.eclipse.aether.artifact.ArtifactProperties.LANGUAGE, language.id()); + this.artifactProperties = new DefaultArtifactProperties(props); } @Override public String getId() { - return dependencyProperties.asMap().get(ArtifactProperties.TYPE); + return artifactProperties.asMap().get(org.eclipse.aether.artifact.ArtifactProperties.TYPE); } @Override - public String getLanguage() { - return dependencyProperties.asMap().get(ArtifactProperties.LANGUAGE); + public Language getLanguage() { + return language; } @Override @@ -73,12 +72,12 @@ public String getClassifier() { } @Override - public DependencyProperties getDependencyProperties() { - return dependencyProperties; + public ArtifactProperties getArtifactProperties() { + return artifactProperties; } @Override public Map getProperties() { - return getDependencyProperties().asMap(); + return getArtifactProperties().asMap(); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java index cebd30cc666a..346d40e5e012 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java @@ -26,9 +26,10 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; import org.apache.maven.api.Type; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.services.LanguageManager; import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.handler.manager.LegacyArtifactHandlerManager; @@ -42,6 +43,8 @@ public class DefaultTypeRegistry extends AbstractEventSpy implements TypeRegistry { private final Map types; + private final LanguageManager languageManager; + private final ConcurrentHashMap usedTypes; private final ConcurrentHashMap legacyTypes; @@ -49,8 +52,10 @@ public class DefaultTypeRegistry extends AbstractEventSpy implements TypeRegistr private final LegacyArtifactHandlerManager manager; @Inject - public DefaultTypeRegistry(Map types, LegacyArtifactHandlerManager manager) { + public DefaultTypeRegistry( + Map types, LanguageManager languageManager, LegacyArtifactHandlerManager manager) { this.types = nonNull(types, "types"); + this.languageManager = nonNull(languageManager, "languageManager"); this.usedTypes = new ConcurrentHashMap<>(); this.legacyTypes = new ConcurrentHashMap<>(); this.manager = nonNull(manager, "artifactHandlerManager"); @@ -80,17 +85,17 @@ public Type getType(String id) { ArtifactHandler handler = manager.getArtifactHandler(id); ArrayList flags = new ArrayList<>(); if (handler.isAddedToClasspath()) { - flags.add(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT); + flags.add(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT); } if (handler.isIncludesDependencies()) { - flags.add(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); + flags.add(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES); } return new DefaultType( id, - handler.getLanguage(), + languageManager.requireLanguageFamily(handler.getLanguage()), handler.getExtension(), handler.getClassifier(), - new DefaultDependencyProperties(flags)); + new DefaultArtifactProperties(flags)); }); } return type; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/language/DefaultLanguageManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/language/DefaultLanguageManager.java new file mode 100644 index 000000000000..c1ccdeaa17e4 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/language/DefaultLanguageManager.java @@ -0,0 +1,47 @@ +/* + * 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.internal.impl.language; + +import javax.inject.Named; +import javax.inject.Singleton; + +import java.util.Objects; +import java.util.Optional; + +import org.apache.maven.api.Language; +import org.apache.maven.api.services.LanguageManager; + +/** + * TODO: this is session scoped as SPI can contribute. + */ +@Named +@Singleton +public class DefaultLanguageManager implements LanguageManager { + @Override + public Optional lookupLanguageFamily(String id) { + if (Objects.equals(Language.NONE.id(), id)) { + return Optional.of(Language.NONE); + } + // TODO: this is now just a shortcut; elaborate this, probably with some SPI LanguageSupport + if (Objects.equals(Language.JAVA_FAMILY.id(), id)) { + return Optional.of(Language.JAVA_FAMILY); + } + return Optional.empty(); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java index d7387a1780b2..2683db3140c3 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java @@ -22,8 +22,9 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(BomTypeProvider.NAME) @@ -34,7 +35,7 @@ public class BomTypeProvider implements Provider { private final Type type; public BomTypeProvider() { - this.type = new DefaultType(NAME, Type.LANGUAGE_NONE, "pom", null, new DefaultDependencyProperties()); + this.type = new DefaultType(NAME, Language.NONE, "pom", null, new DefaultArtifactProperties()); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java index 489ed638bb53..be805b57abcf 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EarTypeProvider.NAME) @@ -37,10 +38,10 @@ public class EarTypeProvider implements Provider { public EarTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "ear", null, - new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java index efbfe05a1cc0..506a1a697f5e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EjbClientTypeProvider.NAME) @@ -37,10 +38,10 @@ public class EjbClientTypeProvider implements Provider { public EjbClientTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "jar", "client", - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java index e6f8fbdb4b5e..316434b61ba4 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EjbTypeProvider.NAME) @@ -37,10 +38,10 @@ public class EjbTypeProvider implements Provider { public EjbTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "jar", null, - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java index 974c34e0ed97..f989384f0b31 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(JarTypeProvider.NAME) @@ -37,10 +38,10 @@ public class JarTypeProvider implements Provider { public JarTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "jar", null, - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java index bef8acf716fd..aa45e054df0a 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java @@ -22,8 +22,9 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(JavaSourceTypeProvider.NAME) @@ -34,7 +35,7 @@ public class JavaSourceTypeProvider implements Provider { private final Type type; public JavaSourceTypeProvider() { - this.type = new DefaultType(NAME, Type.LANGUAGE_JAVA, "jar", "sources", new DefaultDependencyProperties()); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "sources", new DefaultArtifactProperties()); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java index 1ccac4f04b49..a9f9c842a12b 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(JavadocTypeProvider.NAME) @@ -37,10 +38,10 @@ public class JavadocTypeProvider implements Provider { public JavadocTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "jar", "javadoc", - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java index bfdb424c2786..f1d9abc00054 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(MavenPluginTypeProvider.NAME) @@ -37,10 +38,10 @@ public class MavenPluginTypeProvider implements Provider { public MavenPluginTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "jar", null, - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java index 91db9ba182da..7b27092c1d4d 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(ParTypeProvider.NAME) @@ -37,10 +38,10 @@ public class ParTypeProvider implements Provider { public ParTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "par", null, - new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java index fe0f9705d0ea..4c1651773b90 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java @@ -22,8 +22,9 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(PomTypeProvider.NAME) @@ -34,7 +35,7 @@ public class PomTypeProvider implements Provider { private final Type type; public PomTypeProvider() { - this.type = new DefaultType(NAME, Type.LANGUAGE_NONE, "pom", null, new DefaultDependencyProperties()); + this.type = new DefaultType(NAME, Language.NONE, "pom", null, new DefaultArtifactProperties()); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java index ad5accd3cd0c..7e0a180393c1 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(RarTypeProvider.NAME) @@ -37,10 +38,10 @@ public class RarTypeProvider implements Provider { public RarTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "rar", null, - new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java index 6bd7ea2da727..dfd7232d4016 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(TestJarTypeProvider.NAME) @@ -37,10 +38,10 @@ public class TestJarTypeProvider implements Provider { public TestJarTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "jar", "tests", - new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java index a2b339001d46..d5a4d05046a5 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java @@ -22,9 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; +import org.apache.maven.internal.impl.DefaultArtifactProperties; import org.apache.maven.internal.impl.DefaultType; @Named(WarTypeProvider.NAME) @@ -37,10 +38,10 @@ public class WarTypeProvider implements Provider { public WarTypeProvider() { this.type = new DefaultType( NAME, - Type.LANGUAGE_JAVA, + Language.JAVA_FAMILY, "war", null, - new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); + new DefaultArtifactProperties(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES)); } @Override From 37fb446bbc37509bc844d487965029c747f3bf24 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 24 Jan 2024 21:55:31 +0100 Subject: [PATCH 13/31] Step2b --- .../java/org/apache/maven/api/BuildPath.java | 2 +- .../org/apache/maven/api/BuildPathScope.java | 106 +++++++++++++++++- .../org/apache/maven/api/DependencyScope.java | 31 +++++ .../java/org/apache/maven/api/Packaging.java | 16 +++ .../java/org/apache/maven/api/Project.java | 12 +- .../org/apache/maven/api/ProjectScope.java | 76 +++++++++++++ .../maven/api/services/PackagingManager.java | 34 ++++++ .../DefaultLanguageManager.java | 2 +- .../impl/DefaultPackagingManager.java | 82 ++++++++++++++ .../maven/internal/impl/DefaultProject.java | 7 +- ...ginParameterExpressionEvaluatorV4Test.java | 3 +- .../scopes/MavenDependencyScopes.java | 20 ++-- 12 files changed, 374 insertions(+), 17 deletions(-) create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/ProjectScope.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingManager.java rename maven-core/src/main/java/org/apache/maven/internal/impl/{language => }/DefaultLanguageManager.java (97%) create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java index f370bde8b1a2..970e73e063b4 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java @@ -40,7 +40,7 @@ public interface BuildPath { @Nonnull default Language language() { - return buildPathScope().language(); + return project().getLanguage(); } @Nonnull diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java index c63ebd3968ac..3249b5e5936d 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java @@ -18,7 +18,10 @@ */ package org.apache.maven.api; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; @@ -39,8 +42,109 @@ public interface BuildPathScope { String id(); @Nonnull - Language language(); + ProjectScope projectScope(); @Nonnull Collection getDependencyScopes(); + + default BuildPathScope union(BuildPathScope other) { + return new BuildPathScope() { + @Override + public String id() { + return BuildPathScope.this.id() + "+" + other.id(); + } + + @Override + public ProjectScope projectScope() { + return BuildPathScope.this.projectScope().compareTo(other.projectScope()) < 1 + ? other.projectScope() + : BuildPathScope.this.projectScope(); + } + + @Override + public Collection getDependencyScopes() { + HashSet result = new HashSet<>(BuildPathScope.this.getDependencyScopes()); + result.addAll(other.getDependencyScopes()); + return result; + } + }; + } + + BuildPathScope MAIN_COMPILE = new BuildPathScope() { + @Override + public String id() { + return "main-compile"; + } + + @Override + public ProjectScope projectScope() { + return ProjectScope.MAIN; + } + + @Override + public Collection getDependencyScopes() { + return Collections.unmodifiableList( + Arrays.asList(DependencyScope.COMPILE_ONLY, DependencyScope.COMPILE, DependencyScope.PROVIDED)); + } + }; + + BuildPathScope MAIN_RUNTIME = new BuildPathScope() { + @Override + public String id() { + return "main-runtime"; + } + + @Override + public ProjectScope projectScope() { + return ProjectScope.MAIN; + } + + @Override + public Collection getDependencyScopes() { + return Collections.unmodifiableList(Arrays.asList(DependencyScope.COMPILE, DependencyScope.RUNTIME)); + } + }; + + BuildPathScope TEST_COMPILE = new BuildPathScope() { + @Override + public String id() { + return "test-compile"; + } + + @Override + public ProjectScope projectScope() { + return ProjectScope.TEST; + } + + @Override + public Collection getDependencyScopes() { + return Collections.unmodifiableList(Arrays.asList( + DependencyScope.COMPILE, + DependencyScope.PROVIDED, + DependencyScope.TEST_ONLY, + DependencyScope.TEST)); + } + }; + + BuildPathScope TEST_RUNTIME = new BuildPathScope() { + @Override + public String id() { + return "test-runtime"; + } + + @Override + public ProjectScope projectScope() { + return ProjectScope.TEST; + } + + @Override + public Collection getDependencyScopes() { + return Collections.unmodifiableList(Arrays.asList( + DependencyScope.COMPILE, + DependencyScope.RUNTIME, + DependencyScope.PROVIDED, + DependencyScope.TEST, + DependencyScope.TEST_RUNTIME)); + } + }; } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java index ab50e90f23de..de410b77f247 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java @@ -38,6 +38,10 @@ public interface DependencyScope { boolean isTransitive(); + /** + * None. Allows you to declare dependencies (for example to alter reactor build order) but in reality dependencies + * in this scope are not part of any build path scope. + */ DependencyScope NONE = new DependencyScope() { @Override public String id() { @@ -50,6 +54,9 @@ public boolean isTransitive() { } }; + /** + * Compile only. + */ DependencyScope COMPILE_ONLY = new DependencyScope() { @Override public String id() { @@ -62,6 +69,9 @@ public boolean isTransitive() { } }; + /** + * Compile. + */ DependencyScope COMPILE = new DependencyScope() { @Override public String id() { @@ -74,6 +84,9 @@ public boolean isTransitive() { } }; + /** + * Runtime. + */ DependencyScope RUNTIME = new DependencyScope() { @Override public String id() { @@ -86,6 +99,9 @@ public boolean isTransitive() { } }; + /** + * Provided. + */ DependencyScope PROVIDED = new DependencyScope() { @Override public String id() { @@ -98,6 +114,9 @@ public boolean isTransitive() { } }; + /** + * Test compile only. + */ DependencyScope TEST_ONLY = new DependencyScope() { @Override public String id() { @@ -110,6 +129,9 @@ public boolean isTransitive() { } }; + /** + * Test. + */ DependencyScope TEST = new DependencyScope() { @Override public String id() { @@ -122,6 +144,9 @@ public boolean isTransitive() { } }; + /** + * Test runtime. + */ DependencyScope TEST_RUNTIME = new DependencyScope() { @Override public String id() { @@ -134,6 +159,12 @@ public boolean isTransitive() { } }; + /** + * System scope. + *

          + * Important: this scope {@code id} MUST BE KEPT in sync with label in + * {@code org.eclipse.aether.util.artifact.Scopes#SYSTEM}. + */ DependencyScope SYSTEM = new DependencyScope() { @Override public String id() { diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java index 9327178c9802..b2e822f189e0 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java @@ -18,6 +18,8 @@ */ package org.apache.maven.api; +import java.util.Collection; + import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; import org.apache.maven.api.annotations.Nonnull; @@ -30,14 +32,28 @@ @Experimental @Immutable public interface Packaging { + /** + * The packaging id. + */ @Nonnull String id(); + /** + * The language of this packaging. + */ @Nonnull default Language language() { return getType().getLanguage(); } + /** + * The type of main artifact produced by this packaging. + */ @Nonnull Type getType(); + + /** + * Returns the ordered list of {@link BuildPathScope}s. + */ + Collection buildPathScopes(); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java index 1b448f9bc311..948bb2561211 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java @@ -76,7 +76,17 @@ public interface Project { * @see #getArtifacts() */ @Nonnull - String getPackaging(); + Packaging getPackaging(); + + /** + * Returns the project language. It is by default determined by {@link #getPackaging()}. + * + * @see #getPackaging() + */ + @Nonnull + default Language getLanguage() { + return getPackaging().language(); + } /** * Returns the project POM artifact, which is the artifact of the POM of this project. Every project have a POM diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ProjectScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ProjectScope.java new file mode 100644 index 000000000000..6fc06eeac376 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ProjectScope.java @@ -0,0 +1,76 @@ +/* + * 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 org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Immutable; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Project scope. + *

          + * Implementation must have {@code equals()} and {@code hashCode()} implemented, so implementations of this interface + * can be used as keys. + * + * @since 4.0.0 + */ +@Experimental +@Immutable +@SuppressWarnings("checkstyle:magicnumber") +public interface ProjectScope extends Comparable { + @Nonnull + String id(); + + int ordinal(); + + @Override + default int compareTo(ProjectScope o) { + return this.ordinal() - o.ordinal(); + } + + /** + * Main scope. + */ + ProjectScope MAIN = new ProjectScope() { + @Override + public String id() { + return "main"; + } + + @Override + public int ordinal() { + return 10; + } + }; + + /** + * Test scope. + */ + ProjectScope TEST = new ProjectScope() { + @Override + public String id() { + return "test"; + } + + @Override + public int ordinal() { + return 20; + } + }; +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingManager.java new file mode 100644 index 000000000000..07568b4f644d --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingManager.java @@ -0,0 +1,34 @@ +/* + * 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.services; + +import java.util.Optional; + +import org.apache.maven.api.Packaging; +import org.apache.maven.api.Service; +import org.apache.maven.api.annotations.Nonnull; + +public interface PackagingManager extends Service { + @Nonnull + Optional lookupPackaging(String id); + + default Packaging requirePackaging(String id) { + return lookupPackaging(id).orElseThrow(() -> new IllegalArgumentException("Unknown packaging")); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/language/DefaultLanguageManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLanguageManager.java similarity index 97% rename from maven-core/src/main/java/org/apache/maven/internal/impl/language/DefaultLanguageManager.java rename to maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLanguageManager.java index c1ccdeaa17e4..c120eb83c506 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/language/DefaultLanguageManager.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLanguageManager.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.maven.internal.impl.language; +package org.apache.maven.internal.impl; import javax.inject.Named; import javax.inject.Singleton; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java new file mode 100644 index 000000000000..9db7c11ba6bb --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java @@ -0,0 +1,82 @@ +/* + * 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.internal.impl; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import java.util.*; + +import org.apache.maven.api.BuildPathScope; +import org.apache.maven.api.Packaging; +import org.apache.maven.api.Type; +import org.apache.maven.api.services.PackagingManager; +import org.apache.maven.api.services.TypeRegistry; +import org.apache.maven.lifecycle.mapping.LifecycleMapping; + +/** + * TODO: this is session scoped as SPI can contribute. + */ +@Named +@Singleton +public class DefaultPackagingManager implements PackagingManager { + private final Map lifecycleMappings; + + private final TypeRegistry typeRegistry; + + @Inject + public DefaultPackagingManager(Map lifecycleMappings, TypeRegistry typeRegistry) { + this.lifecycleMappings = lifecycleMappings; + this.typeRegistry = typeRegistry; + } + + @Override + public Optional lookupPackaging(String id) { + LifecycleMapping lifecycleMapping = lifecycleMappings.get(id); + if (lifecycleMapping == null) { + return Optional.empty(); + } + Type type = typeRegistry.getType(id); + if (type == null) { + return Optional.empty(); + } + + return Optional.of(new Packaging() { + @Override + public String id() { + return id; + } + + @Override + public Type getType() { + return type; + } + + @Override + public Collection buildPathScopes() { + return Collections.unmodifiableList(Arrays.asList( + BuildPathScope.MAIN_COMPILE, + BuildPathScope.MAIN_RUNTIME, + BuildPathScope.TEST_COMPILE, + BuildPathScope.TEST_RUNTIME)); + } + }); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java index f438261aee5d..bd018ab05158 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java @@ -27,6 +27,7 @@ import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.model.DependencyManagement; import org.apache.maven.api.model.Model; +import org.apache.maven.api.services.PackagingManager; import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.project.MavenProject; import org.apache.maven.project.artifact.ProjectArtifact; @@ -38,10 +39,12 @@ public class DefaultProject implements Project { private final InternalSession session; private final MavenProject project; + private final Packaging packaging; public DefaultProject(InternalSession session, MavenProject project) { this.session = session; this.project = project; + this.packaging = session.getService(PackagingManager.class).requirePackaging(project.getPackaging()); } public InternalSession getSession() { @@ -86,8 +89,8 @@ public List getArtifacts() { @Nonnull @Override - public String getPackaging() { - return project.getPackaging(); + public Packaging getPackaging() { + return packaging; } @Nonnull diff --git a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java index d90d9052e632..689ccbdca495 100644 --- a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java +++ b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java @@ -32,9 +32,8 @@ import org.apache.maven.AbstractCoreMavenComponentTestCase; import org.apache.maven.RepositoryUtils; -import org.apache.maven.api.Artifact; +import org.apache.maven.api.*; import org.apache.maven.api.MojoExecution; -import org.apache.maven.api.Session; import org.apache.maven.artifact.DefaultArtifact; import org.apache.maven.artifact.handler.DefaultArtifactHandler; import org.apache.maven.artifact.repository.ArtifactRepository; diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/scopes/MavenDependencyScopes.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/scopes/MavenDependencyScopes.java index 2d074a4e070a..fa0fe5b8f71e 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/scopes/MavenDependencyScopes.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/scopes/MavenDependencyScopes.java @@ -18,7 +18,7 @@ */ package org.apache.maven.repository.internal.scopes; -import org.eclipse.aether.util.artifact.DependencyScopes; +import org.apache.maven.api.DependencyScope; /** * The dependency scopes used for Java dependencies in Maven. This class defines labels only, that are doing pass-thru @@ -31,21 +31,23 @@ public final class MavenDependencyScopes { /** * Important: keep this label in sync with Resolver. */ - public static final String SYSTEM = DependencyScopes.SYSTEM; + public static final String SYSTEM = DependencyScope.SYSTEM.id(); - public static final String COMPILE_ONLY = "compile-only"; + public static final String NONE = DependencyScope.NONE.id(); - public static final String COMPILE = "compile"; + public static final String COMPILE_ONLY = DependencyScope.COMPILE_ONLY.id(); - public static final String PROVIDED = "provided"; + public static final String COMPILE = DependencyScope.COMPILE.id(); - public static final String RUNTIME = "runtime"; + public static final String PROVIDED = DependencyScope.PROVIDED.id(); - public static final String TEST_ONLY = "test-only"; + public static final String RUNTIME = DependencyScope.RUNTIME.id(); - public static final String TEST = "test"; + public static final String TEST_ONLY = DependencyScope.TEST_ONLY.id(); - public static final String TEST_RUNTIME = "test-runtime"; + public static final String TEST = DependencyScope.TEST.id(); + + public static final String TEST_RUNTIME = DependencyScope.TEST_RUNTIME.id(); private MavenDependencyScopes() { // hide constructor From 944c3910b4b00c3608b125377a0203171aa284c7 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 24 Jan 2024 22:01:21 +0100 Subject: [PATCH 14/31] Remove unrelated --- .../src/main/java/org/apache/maven/api/Packaging.java | 5 ----- .../maven/internal/impl/DefaultPackagingManager.java | 10 ---------- 2 files changed, 15 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java index b2e822f189e0..404f6d28db4d 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java @@ -51,9 +51,4 @@ default Language language() { */ @Nonnull Type getType(); - - /** - * Returns the ordered list of {@link BuildPathScope}s. - */ - Collection buildPathScopes(); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java index 9db7c11ba6bb..7254bbeca61e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java @@ -24,7 +24,6 @@ import java.util.*; -import org.apache.maven.api.BuildPathScope; import org.apache.maven.api.Packaging; import org.apache.maven.api.Type; import org.apache.maven.api.services.PackagingManager; @@ -68,15 +67,6 @@ public String id() { public Type getType() { return type; } - - @Override - public Collection buildPathScopes() { - return Collections.unmodifiableList(Arrays.asList( - BuildPathScope.MAIN_COMPILE, - BuildPathScope.MAIN_RUNTIME, - BuildPathScope.TEST_COMPILE, - BuildPathScope.TEST_RUNTIME)); - } }); } } From dcc0498ac0d7d323df76e5c1c69c63847c90a77a Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 24 Jan 2024 22:10:30 +0100 Subject: [PATCH 15/31] Remove unused --- .../src/main/java/org/apache/maven/api/Packaging.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java index 404f6d28db4d..94fddc0e8191 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java @@ -18,8 +18,6 @@ */ package org.apache.maven.api; -import java.util.Collection; - import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; import org.apache.maven.api.annotations.Nonnull; From 22b31adc54dbbe43563c9c69e0199486048d6208 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 24 Jan 2024 22:14:58 +0100 Subject: [PATCH 16/31] Add TODO --- .../src/main/java/org/apache/maven/api/Language.java | 1 + 1 file changed, 1 insertion(+) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java index 700c53f0da86..9c228da08f77 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java @@ -60,6 +60,7 @@ public boolean isCompatibleWith(Language language) { } }; + // TODO: this should be moved out from here to Java Support (builtin into core) Language JAVA_FAMILY = new Language() { @Override public String id() { From dc4b1e70f1e29d0a1c22c5cabc4d713c11acbded Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 11:27:23 +0100 Subject: [PATCH 17/31] Undo ArtifactProperties and Artifact#isSnapshot changes for now --- .../java/org/apache/maven/api/Artifact.java | 8 ----- .../java/org/apache/maven/api/Dependency.java | 8 +++++ ...perties.java => DependencyProperties.java} | 4 +-- .../main/java/org/apache/maven/api/Type.java | 6 ++-- .../maven/api/services/VersionParser.java | 8 ++--- .../internal/aether/TypeRegistryAdapter.java | 2 +- .../maven/internal/impl/DefaultArtifact.java | 11 ++----- .../internal/impl/DefaultDependency.java | 26 ++++++++++------- ....java => DefaultDependencyProperties.java} | 16 ++++++---- .../impl/DefaultPackagingManager.java | 3 +- .../maven/internal/impl/DefaultType.java | 29 +++++++++++-------- .../internal/impl/DefaultTypeRegistry.java | 8 ++--- .../internal/impl/types/BomTypeProvider.java | 4 +-- .../internal/impl/types/EarTypeProvider.java | 6 ++-- .../impl/types/EjbClientTypeProvider.java | 6 ++-- .../internal/impl/types/EjbTypeProvider.java | 6 ++-- .../internal/impl/types/JarTypeProvider.java | 6 ++-- .../impl/types/JavaSourceTypeProvider.java | 4 +-- .../impl/types/JavadocTypeProvider.java | 6 ++-- .../impl/types/MavenPluginTypeProvider.java | 6 ++-- .../internal/impl/types/ParTypeProvider.java | 6 ++-- .../internal/impl/types/PomTypeProvider.java | 4 +-- .../internal/impl/types/RarTypeProvider.java | 6 ++-- .../impl/types/TestJarTypeProvider.java | 6 ++-- .../internal/impl/types/WarTypeProvider.java | 6 ++-- ...ginParameterExpressionEvaluatorV4Test.java | 3 +- 26 files changed, 107 insertions(+), 97 deletions(-) rename api/maven-api-core/src/main/java/org/apache/maven/api/{ArtifactProperties.java => DependencyProperties.java} (95%) rename maven-core/src/main/java/org/apache/maven/internal/impl/{DefaultArtifactProperties.java => DefaultDependencyProperties.java} (78%) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java index e92ffd732f1e..bdc18b958c45 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java @@ -105,14 +105,6 @@ default String key() { */ boolean isSnapshot(); - /** - * The artifact properties. - * - * @return the artifact properties, never {@code null} - */ - @Nonnull - ArtifactProperties getArtifactProperties(); - /** * Shortcut for {@code session.createArtifactCoordinate(artifact)} * diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java index 888e247fe1cf..efad1415adf8 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java @@ -30,6 +30,14 @@ public interface Dependency extends Artifact { @Nonnull Type getType(); + /** + * The dependency properties. + * + * @return the dependency properties, never {@code null} + */ + @Nonnull + DependencyProperties getDependencyProperties(); + @Nonnull Scope getScope(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java similarity index 95% rename from api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactProperties.java rename to api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java index fc3c197ccc45..4bcb5caeaf56 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactProperties.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java @@ -25,13 +25,13 @@ import org.apache.maven.api.annotations.Nonnull; /** - * Artifact properties supported by Maven Core. + * Dependency properties supported by Maven Core. * * @since 4.0.0 */ @Experimental @Immutable -public interface ArtifactProperties { +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. diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java index 473d9a661152..862049facf6e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java @@ -82,7 +82,7 @@ public interface Type { * @return if the artifact should be added to the build path */ default boolean isBuildPathConstituent() { - return getArtifactProperties().checkFlag(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT); + return getDependencyProperties().checkFlag(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT); } /** @@ -93,7 +93,7 @@ default boolean isBuildPathConstituent() { * @return if the artifact's dependencies are included in the artifact */ default boolean isIncludesDependencies() { - return getArtifactProperties().checkFlag(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES); + return getDependencyProperties().checkFlag(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); } /** @@ -102,5 +102,5 @@ default boolean isIncludesDependencies() { * @return the default properties, never {@code null}. */ @Nonnull - ArtifactProperties getArtifactProperties(); + DependencyProperties getDependencyProperties(); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java index a4f8484df042..d344122d7f19 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java @@ -18,7 +18,10 @@ */ package org.apache.maven.api.services; -import org.apache.maven.api.*; +import org.apache.maven.api.Service; +import org.apache.maven.api.Version; +import org.apache.maven.api.VersionConstraint; +import org.apache.maven.api.VersionRange; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; @@ -63,9 +66,6 @@ public interface VersionParser extends Service { /** * Checks whether a given artifact version is considered a {@code SNAPSHOT} or not. - *

          - * In case there is {@link Artifact} in scope, the recommended way to perform this check is - * use of {@link Artifact#isSnapshot()} instead. */ boolean isSnapshot(@Nonnull String version); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java index 1d0dca3ee2d9..b5f3f9c61437 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java +++ b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java @@ -45,7 +45,7 @@ public ArtifactType get(String typeId) { type.getLanguage(), type.getExtension(), type.getClassifier(), - type.getArtifactProperties()); + type.getDependencyProperties()); } return null; } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java index 35ca4439593c..563797f05c49 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java @@ -22,9 +22,9 @@ import org.apache.maven.api.Artifact; import org.apache.maven.api.ArtifactCoordinate; -import org.apache.maven.api.ArtifactProperties; import org.apache.maven.api.Version; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.repository.internal.DefaultModelVersionParser; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -34,13 +34,11 @@ public class DefaultArtifact implements Artifact { private final @Nonnull InternalSession session; private final @Nonnull org.eclipse.aether.artifact.Artifact artifact; - private final @Nonnull ArtifactProperties artifactProperties; private final String key; public DefaultArtifact(@Nonnull InternalSession session, @Nonnull org.eclipse.aether.artifact.Artifact artifact) { this.session = nonNull(session, "session"); this.artifact = nonNull(artifact, "artifact"); - this.artifactProperties = new DefaultArtifactProperties(artifact.getProperties()); this.key = getGroupId() + ':' + getArtifactId() @@ -97,12 +95,7 @@ public String getClassifier() { @Override public boolean isSnapshot() { - return artifact.isSnapshot(); - } - - @Override - public ArtifactProperties getArtifactProperties() { - return artifactProperties; + return DefaultModelVersionParser.checkSnapshot(artifact.getVersion()); } @Nonnull diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java index 40381e965e24..3f2f06893ebf 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java @@ -20,25 +20,33 @@ import java.util.Objects; -import org.apache.maven.api.*; +import org.apache.maven.api.Artifact; +import org.apache.maven.api.Dependency; +import org.apache.maven.api.DependencyCoordinate; +import org.apache.maven.api.DependencyProperties; +import org.apache.maven.api.Scope; +import org.apache.maven.api.Type; +import org.apache.maven.api.Version; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.services.TypeRegistry; +import org.apache.maven.repository.internal.DefaultModelVersionParser; +import org.eclipse.aether.artifact.ArtifactProperties; import static org.apache.maven.internal.impl.Utils.nonNull; public class DefaultDependency implements Dependency { private final InternalSession session; private final org.eclipse.aether.graph.Dependency dependency; - private final ArtifactProperties artifactProperties; + private final DependencyProperties dependencyProperties; private final String key; public DefaultDependency( @Nonnull InternalSession session, @Nonnull org.eclipse.aether.graph.Dependency dependency) { this.session = nonNull(session, "session"); this.dependency = nonNull(dependency, "dependency"); - this.artifactProperties = - new DefaultArtifactProperties(dependency.getArtifact().getProperties()); + this.dependencyProperties = + new DefaultDependencyProperties(dependency.getArtifact().getProperties()); this.key = getGroupId() + ':' + getArtifactId() @@ -93,20 +101,18 @@ public String getExtension() { public Type getType() { String type = dependency .getArtifact() - .getProperty( - org.eclipse.aether.artifact.ArtifactProperties.TYPE, - dependency.getArtifact().getExtension()); + .getProperty(ArtifactProperties.TYPE, dependency.getArtifact().getExtension()); return session.getService(TypeRegistry.class).getType(type); } @Override - public ArtifactProperties getArtifactProperties() { - return artifactProperties; + public DependencyProperties getDependencyProperties() { + return dependencyProperties; } @Override public boolean isSnapshot() { - return dependency.getArtifact().isSnapshot(); + return DefaultModelVersionParser.checkSnapshot(dependency.getArtifact().getVersion()); } @Nonnull diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java similarity index 78% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactProperties.java rename to maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java index f3329620c42c..2ee780713034 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactProperties.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java @@ -18,9 +18,13 @@ */ package org.apache.maven.internal.impl; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.annotations.Nonnull; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -28,14 +32,14 @@ /** * Default implementation of artifact properties. */ -public class DefaultArtifactProperties implements ArtifactProperties { +public class DefaultDependencyProperties implements DependencyProperties { private final Map properties; - public DefaultArtifactProperties(String... flags) { + public DefaultDependencyProperties(String... flags) { this(Arrays.asList(flags)); } - public DefaultArtifactProperties(@Nonnull Collection flags) { + public DefaultDependencyProperties(@Nonnull Collection flags) { nonNull(flags, "flags"); HashMap map = new HashMap<>(); for (String flag : flags) { @@ -44,7 +48,7 @@ public DefaultArtifactProperties(@Nonnull Collection flags) { this.properties = Collections.unmodifiableMap(map); } - public DefaultArtifactProperties(@Nonnull Map properties) { + public DefaultDependencyProperties(@Nonnull Map properties) { this.properties = Collections.unmodifiableMap(nonNull(properties, "properties")); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java index 7254bbeca61e..8364b1192670 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java @@ -22,7 +22,8 @@ import javax.inject.Named; import javax.inject.Singleton; -import java.util.*; +import java.util.Map; +import java.util.Optional; import org.apache.maven.api.Packaging; import org.apache.maven.api.Type; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java index 4098cc9c058a..9b272c31a4b4 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java @@ -21,9 +21,10 @@ import java.util.HashMap; import java.util.Map; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; +import org.eclipse.aether.artifact.ArtifactProperties; import org.eclipse.aether.artifact.ArtifactType; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -35,25 +36,29 @@ public class DefaultType implements Type, ArtifactType { private final String classifier; - private final ArtifactProperties artifactProperties; + private final DependencyProperties dependencyProperties; public DefaultType( - String id, Language language, String extension, String classifier, ArtifactProperties artifactProperties) { + String id, + Language language, + String extension, + String classifier, + DependencyProperties dependencyProperties) { nonNull(id, "id"); nonNull(language, "language"); this.language = language; this.extension = nonNull(extension, "extension"); this.classifier = classifier; - nonNull(artifactProperties, "artifactProperties"); - HashMap props = new HashMap<>(artifactProperties.asMap()); - props.put(org.eclipse.aether.artifact.ArtifactProperties.TYPE, id); - props.put(org.eclipse.aether.artifact.ArtifactProperties.LANGUAGE, language.id()); - this.artifactProperties = new DefaultArtifactProperties(props); + nonNull(dependencyProperties, "dependencyProperties"); + HashMap props = new HashMap<>(dependencyProperties.asMap()); + props.put(ArtifactProperties.TYPE, id); + props.put(ArtifactProperties.LANGUAGE, language.id()); + this.dependencyProperties = new DefaultDependencyProperties(props); } @Override public String getId() { - return artifactProperties.asMap().get(org.eclipse.aether.artifact.ArtifactProperties.TYPE); + return dependencyProperties.asMap().get(ArtifactProperties.TYPE); } @Override @@ -72,12 +77,12 @@ public String getClassifier() { } @Override - public ArtifactProperties getArtifactProperties() { - return artifactProperties; + public DependencyProperties getDependencyProperties() { + return dependencyProperties; } @Override public Map getProperties() { - return getArtifactProperties().asMap(); + return getDependencyProperties().asMap(); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java index 346d40e5e012..41174da40f5d 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java @@ -26,7 +26,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Type; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.services.LanguageManager; @@ -85,17 +85,17 @@ public Type getType(String id) { ArtifactHandler handler = manager.getArtifactHandler(id); ArrayList flags = new ArrayList<>(); if (handler.isAddedToClasspath()) { - flags.add(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT); + flags.add(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT); } if (handler.isIncludesDependencies()) { - flags.add(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES); + flags.add(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); } return new DefaultType( id, languageManager.requireLanguageFamily(handler.getLanguage()), handler.getExtension(), handler.getClassifier(), - new DefaultArtifactProperties(flags)); + new DefaultDependencyProperties(flags)); }); } return type; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java index 2683db3140c3..bc7f8042c9da 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java @@ -24,7 +24,7 @@ import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(BomTypeProvider.NAME) @@ -35,7 +35,7 @@ public class BomTypeProvider implements Provider { private final Type type; public BomTypeProvider() { - this.type = new DefaultType(NAME, Language.NONE, "pom", null, new DefaultArtifactProperties()); + this.type = new DefaultType(NAME, Language.NONE, "pom", null, new DefaultDependencyProperties()); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java index be805b57abcf..28dee7cf85c3 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EarTypeProvider.NAME) @@ -41,7 +41,7 @@ public EarTypeProvider() { Language.JAVA_FAMILY, "ear", null, - new DefaultArtifactProperties(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES)); + new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java index 506a1a697f5e..03a47874e932 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EjbClientTypeProvider.NAME) @@ -41,7 +41,7 @@ public EjbClientTypeProvider() { Language.JAVA_FAMILY, "jar", "client", - new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); + new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java index 316434b61ba4..ed3f50c7928a 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EjbTypeProvider.NAME) @@ -41,7 +41,7 @@ public EjbTypeProvider() { Language.JAVA_FAMILY, "jar", null, - new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); + new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java index f989384f0b31..a4221fbed3d9 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(JarTypeProvider.NAME) @@ -41,7 +41,7 @@ public JarTypeProvider() { Language.JAVA_FAMILY, "jar", null, - new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); + new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java index aa45e054df0a..d16891826505 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java @@ -24,7 +24,7 @@ import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(JavaSourceTypeProvider.NAME) @@ -35,7 +35,7 @@ public class JavaSourceTypeProvider implements Provider { private final Type type; public JavaSourceTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "sources", new DefaultArtifactProperties()); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "sources", new DefaultDependencyProperties()); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java index a9f9c842a12b..cfe86c51c653 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(JavadocTypeProvider.NAME) @@ -41,7 +41,7 @@ public JavadocTypeProvider() { Language.JAVA_FAMILY, "jar", "javadoc", - new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); + new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java index f1d9abc00054..128e3ee85613 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(MavenPluginTypeProvider.NAME) @@ -41,7 +41,7 @@ public MavenPluginTypeProvider() { Language.JAVA_FAMILY, "jar", null, - new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); + new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java index 7b27092c1d4d..d1dda01e349a 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(ParTypeProvider.NAME) @@ -41,7 +41,7 @@ public ParTypeProvider() { Language.JAVA_FAMILY, "par", null, - new DefaultArtifactProperties(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES)); + new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java index 4c1651773b90..b3a078fd2adc 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java @@ -24,7 +24,7 @@ import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(PomTypeProvider.NAME) @@ -35,7 +35,7 @@ public class PomTypeProvider implements Provider { private final Type type; public PomTypeProvider() { - this.type = new DefaultType(NAME, Language.NONE, "pom", null, new DefaultArtifactProperties()); + this.type = new DefaultType(NAME, Language.NONE, "pom", null, new DefaultDependencyProperties()); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java index 7e0a180393c1..59b0a2882786 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(RarTypeProvider.NAME) @@ -41,7 +41,7 @@ public RarTypeProvider() { Language.JAVA_FAMILY, "rar", null, - new DefaultArtifactProperties(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES)); + new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java index dfd7232d4016..11ceb7ef2d04 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(TestJarTypeProvider.NAME) @@ -41,7 +41,7 @@ public TestJarTypeProvider() { Language.JAVA_FAMILY, "jar", "tests", - new DefaultArtifactProperties(ArtifactProperties.FLAG_BUILD_PATH_CONSTITUENT)); + new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java index d5a4d05046a5..d9d36ea277cf 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java @@ -22,10 +22,10 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.ArtifactProperties; +import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultArtifactProperties; +import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(WarTypeProvider.NAME) @@ -41,7 +41,7 @@ public WarTypeProvider() { Language.JAVA_FAMILY, "war", null, - new DefaultArtifactProperties(ArtifactProperties.FLAG_INCLUDES_DEPENDENCIES)); + new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); } @Override diff --git a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java index 689ccbdca495..d90d9052e632 100644 --- a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java +++ b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java @@ -32,8 +32,9 @@ import org.apache.maven.AbstractCoreMavenComponentTestCase; import org.apache.maven.RepositoryUtils; -import org.apache.maven.api.*; +import org.apache.maven.api.Artifact; import org.apache.maven.api.MojoExecution; +import org.apache.maven.api.Session; import org.apache.maven.artifact.DefaultArtifact; import org.apache.maven.artifact.handler.DefaultArtifactHandler; import org.apache.maven.artifact.repository.ArtifactRepository; From 3e3aa04a87fd6596b3bf29fa74b59dcdaf90249c Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 11:45:11 +0100 Subject: [PATCH 18/31] Fix UT --- .../org/apache/maven/AbstractCoreMavenComponentTestCase.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java index 8feff0671724..8fb0163fbdab 100644 --- a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java +++ b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java @@ -34,6 +34,7 @@ import org.apache.maven.execution.DefaultMavenExecutionResult; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenSession; +import org.apache.maven.internal.impl.DefaultLookup; import org.apache.maven.internal.impl.DefaultSessionFactory; import org.apache.maven.model.Build; import org.apache.maven.model.Dependency; @@ -149,7 +150,8 @@ protected MavenSession createMavenSession(File pom, Properties executionProperti initRepoSession(configuration); DefaultSessionFactory defaultSessionFactory = - new DefaultSessionFactory(mock(RepositorySystem.class), null, null, null); + new DefaultSessionFactory(mock(RepositorySystem.class), + null, new DefaultLookup(container), null); MavenSession session = new MavenSession( getContainer(), configuration.getRepositorySession(), request, new DefaultMavenExecutionResult()); From 25369293f7e620996e2b33cdcb7b24f3922b0a67 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 14:48:10 +0100 Subject: [PATCH 19/31] Introduce "extensible enum" and provides registries, SPI providers, etc... --- .../org/apache/maven/api/BuildPathScope.java | 141 ++++-------------- .../maven/api/DependencyProperties.java | 4 - .../org/apache/maven/api/DependencyScope.java | 115 ++------------ .../org/apache/maven/api/ExtensibleEnum.java | 37 +++++ .../org/apache/maven/api/ExtensibleEnums.java | 118 +++++++++++++++ .../java/org/apache/maven/api/Language.java | 73 +-------- .../java/org/apache/maven/api/Packaging.java | 2 +- .../org/apache/maven/api/ProjectScope.java | 40 +---- .../java/org/apache/maven/api/Session.java | 14 ++ .../main/java/org/apache/maven/api/Type.java | 4 +- .../api/services/BuildPathScopeRegistry.java | 23 +++ .../DependencyCoordinateFactoryRequest.java | 2 +- .../api/services/DependencyScopeRegistry.java | 23 +++ ...nager.java => ExtensibleEnumRegistry.java} | 10 +- .../maven/api/services/LanguageRegistry.java | 28 +--- ...ingManager.java => PackagingRegistry.java} | 13 +- .../api/services/ProjectScopeRegistry.java | 26 ++++ .../maven/api/services/TypeRegistry.java | 5 +- .../maven/api/spi/BuildPathScopeProvider.java | 23 +++ .../api/spi/DependencyScopeProvider.java | 23 +++ .../maven/api/spi/ExtensibleEnumProvider.java | 28 ++++ .../maven/api/spi/LanguageProvider.java | 23 +++ .../maven/api/spi/PackagingProvider.java | 23 +++ .../maven/api/spi/ProjectScopeProvider.java | 23 +++ .../DefaultArtifactHandlerManager.java | 2 +- .../internal/aether/TypeRegistryAdapter.java | 4 +- .../maven/internal/impl/AbstractSession.java | 30 ++++ .../internal/impl/DefaultDependency.java | 2 +- .../impl/DefaultDependencyCoordinate.java | 2 +- ...ger.java => DefaultPackagingRegistry.java} | 10 +- .../maven/internal/impl/DefaultProject.java | 6 +- .../maven/internal/impl/DefaultType.java | 7 +- .../internal/impl/DefaultTypeRegistry.java | 18 ++- .../impl/ExtensibleEnumRegistries.java | 115 ++++++++++++++ .../AbstractCoreMavenComponentTestCase.java | 3 +- 35 files changed, 632 insertions(+), 388 deletions(-) create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnum.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/BuildPathScopeRegistry.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyScopeRegistry.java rename api/maven-api-core/src/main/java/org/apache/maven/api/services/{LanguageManager.java => ExtensibleEnumRegistry.java} (75%) rename maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLanguageManager.java => api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageRegistry.java (51%) rename api/maven-api-core/src/main/java/org/apache/maven/api/services/{PackagingManager.java => PackagingRegistry.java} (69%) create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectScopeRegistry.java create mode 100644 api/maven-api-spi/src/main/java/org/apache/maven/api/spi/BuildPathScopeProvider.java create mode 100644 api/maven-api-spi/src/main/java/org/apache/maven/api/spi/DependencyScopeProvider.java create mode 100644 api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ExtensibleEnumProvider.java create mode 100644 api/maven-api-spi/src/main/java/org/apache/maven/api/spi/LanguageProvider.java create mode 100644 api/maven-api-spi/src/main/java/org/apache/maven/api/spi/PackagingProvider.java create mode 100644 api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ProjectScopeProvider.java rename maven-core/src/main/java/org/apache/maven/internal/impl/{DefaultPackagingManager.java => DefaultPackagingRegistry.java} (85%) create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java index 3249b5e5936d..3142ee39bd71 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java @@ -18,15 +18,14 @@ */ package org.apache.maven.api; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; +import java.util.*; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; import org.apache.maven.api.annotations.Nonnull; +import static org.apache.maven.api.ExtensibleEnums.buildPathScope; + /** * Build path scope. *

          @@ -37,114 +36,38 @@ */ @Experimental @Immutable -public interface BuildPathScope { - @Nonnull - String id(); +public interface BuildPathScope extends ExtensibleEnum { @Nonnull ProjectScope projectScope(); @Nonnull - Collection getDependencyScopes(); - - default BuildPathScope union(BuildPathScope other) { - return new BuildPathScope() { - @Override - public String id() { - return BuildPathScope.this.id() + "+" + other.id(); - } - - @Override - public ProjectScope projectScope() { - return BuildPathScope.this.projectScope().compareTo(other.projectScope()) < 1 - ? other.projectScope() - : BuildPathScope.this.projectScope(); - } - - @Override - public Collection getDependencyScopes() { - HashSet result = new HashSet<>(BuildPathScope.this.getDependencyScopes()); - result.addAll(other.getDependencyScopes()); - return result; - } - }; - } - - BuildPathScope MAIN_COMPILE = new BuildPathScope() { - @Override - public String id() { - return "main-compile"; - } - - @Override - public ProjectScope projectScope() { - return ProjectScope.MAIN; - } - - @Override - public Collection getDependencyScopes() { - return Collections.unmodifiableList( - Arrays.asList(DependencyScope.COMPILE_ONLY, DependencyScope.COMPILE, DependencyScope.PROVIDED)); - } - }; - - BuildPathScope MAIN_RUNTIME = new BuildPathScope() { - @Override - public String id() { - return "main-runtime"; - } - - @Override - public ProjectScope projectScope() { - return ProjectScope.MAIN; - } - - @Override - public Collection getDependencyScopes() { - return Collections.unmodifiableList(Arrays.asList(DependencyScope.COMPILE, DependencyScope.RUNTIME)); - } - }; - - BuildPathScope TEST_COMPILE = new BuildPathScope() { - @Override - public String id() { - return "test-compile"; - } - - @Override - public ProjectScope projectScope() { - return ProjectScope.TEST; - } - - @Override - public Collection getDependencyScopes() { - return Collections.unmodifiableList(Arrays.asList( - DependencyScope.COMPILE, - DependencyScope.PROVIDED, - DependencyScope.TEST_ONLY, - DependencyScope.TEST)); - } - }; - - BuildPathScope TEST_RUNTIME = new BuildPathScope() { - @Override - public String id() { - return "test-runtime"; - } - - @Override - public ProjectScope projectScope() { - return ProjectScope.TEST; - } - - @Override - public Collection getDependencyScopes() { - return Collections.unmodifiableList(Arrays.asList( - DependencyScope.COMPILE, - DependencyScope.RUNTIME, - DependencyScope.PROVIDED, - DependencyScope.TEST, - DependencyScope.TEST_RUNTIME)); - } - }; + Set getDependencyScopes(); + + BuildPathScope MAIN_COMPILE = buildPathScope( + "main-compile", + ProjectScope.MAIN, + DependencyScope.COMPILE_ONLY, + DependencyScope.COMPILE, + DependencyScope.PROVIDED); + + BuildPathScope MAIN_RUNTIME = + buildPathScope("main-runtime", ProjectScope.MAIN, DependencyScope.COMPILE, DependencyScope.RUNTIME); + + BuildPathScope TEST_COMPILE = buildPathScope( + "test-compile", + ProjectScope.TEST, + DependencyScope.COMPILE, + DependencyScope.PROVIDED, + DependencyScope.TEST_ONLY, + DependencyScope.TEST); + + BuildPathScope TEST_RUNTIME = buildPathScope( + "test-runtime", + ProjectScope.TEST, + DependencyScope.COMPILE, + DependencyScope.RUNTIME, + DependencyScope.PROVIDED, + DependencyScope.TEST, + DependencyScope.TEST_RUNTIME); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java index 4bcb5caeaf56..ad52851cd458 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java @@ -35,16 +35,12 @@ 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. - *

          - * Important: this flag must be kept in sync with resolver! (as is used during collection) */ String FLAG_INCLUDES_DEPENDENCIES = "includesDependencies"; /** * Boolean flag telling that dependency is meant to be part of build path. Value of this key should be parsed with * {@link Boolean#parseBoolean(String)} to obtain value. - *

          - * Important: this flag must be kept in sync with resolver! (as is used during collection) */ String FLAG_BUILD_PATH_CONSTITUENT = "constitutesBuildPath"; diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java index de410b77f247..ab64575b8cda 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java @@ -20,7 +20,8 @@ import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; -import org.apache.maven.api.annotations.Nonnull; + +import static org.apache.maven.api.ExtensibleEnums.dependencyScope; /** * Dependency scope. @@ -32,9 +33,7 @@ */ @Experimental @Immutable -public interface DependencyScope { - @Nonnull - String id(); +public interface DependencyScope extends ExtensibleEnum { boolean isTransitive(); @@ -42,122 +41,42 @@ public interface DependencyScope { * None. Allows you to declare dependencies (for example to alter reactor build order) but in reality dependencies * in this scope are not part of any build path scope. */ - DependencyScope NONE = new DependencyScope() { - @Override - public String id() { - return "none"; - } - - @Override - public boolean isTransitive() { - return false; - } - }; + DependencyScope NONE = dependencyScope("none", false); /** * Compile only. */ - DependencyScope COMPILE_ONLY = new DependencyScope() { - @Override - public String id() { - return "compile-only"; - } - - @Override - public boolean isTransitive() { - return false; - } - }; + DependencyScope COMPILE_ONLY = dependencyScope("compile-only", false); /** * Compile. */ - DependencyScope COMPILE = new DependencyScope() { - @Override - public String id() { - return "compile"; - } - - @Override - public boolean isTransitive() { - return true; - } - }; + DependencyScope COMPILE = dependencyScope("compile", true); /** * Runtime. */ - DependencyScope RUNTIME = new DependencyScope() { - @Override - public String id() { - return "runtime"; - } - - @Override - public boolean isTransitive() { - return true; - } - }; + DependencyScope RUNTIME = dependencyScope("runtime", true); /** * Provided. */ - DependencyScope PROVIDED = new DependencyScope() { - @Override - public String id() { - return "provided"; - } - - @Override - public boolean isTransitive() { - return false; - } - }; + DependencyScope PROVIDED = dependencyScope("provided", false); /** * Test compile only. */ - DependencyScope TEST_ONLY = new DependencyScope() { - @Override - public String id() { - return "test-only"; - } - - @Override - public boolean isTransitive() { - return false; - } - }; + DependencyScope TEST_ONLY = dependencyScope("test-only", false); /** * Test. */ - DependencyScope TEST = new DependencyScope() { - @Override - public String id() { - return "test"; - } - - @Override - public boolean isTransitive() { - return false; - } - }; + DependencyScope TEST = dependencyScope("test", false); /** * Test runtime. */ - DependencyScope TEST_RUNTIME = new DependencyScope() { - @Override - public String id() { - return "test-runtime"; - } - - @Override - public boolean isTransitive() { - return false; - } - }; + DependencyScope TEST_RUNTIME = dependencyScope("test-runtime", true); /** * System scope. @@ -165,15 +84,5 @@ public boolean isTransitive() { * Important: this scope {@code id} MUST BE KEPT in sync with label in * {@code org.eclipse.aether.util.artifact.Scopes#SYSTEM}. */ - DependencyScope SYSTEM = new DependencyScope() { - @Override - public String id() { - return "system"; - } - - @Override - public boolean isTransitive() { - return false; - } - }; + DependencyScope SYSTEM = dependencyScope("system", false); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnum.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnum.java new file mode 100644 index 000000000000..87d80075dd5a --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnum.java @@ -0,0 +1,37 @@ +/* + * 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 org.apache.maven.api.annotations.Nonnull; + +/** + * Implementation must have {@code equals()} and {@code hashCode()} implemented, so implementations of this interface + * can be used as keys. + */ +public interface ExtensibleEnum { + + /** + * The {@code id} uniquely represents a value for this extensible enum. + * This id should be used to compute the equality and hash code for the instance. + * + * @return the id + */ + @Nonnull + String id(); +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java new file mode 100644 index 000000000000..60f394b30b86 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java @@ -0,0 +1,118 @@ +/* + * 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.util.*; + +abstract class ExtensibleEnums { + + static Language language(String id) { + return new DefaultLanguage(id); + } + + static DependencyScope dependencyScope(String id, boolean transitive) { + return new DefaultDependencyScope(id, transitive); + } + + static BuildPathScope buildPathScope(String id, ProjectScope projectScope, DependencyScope... dependencyScopes) { + return new DefaultBuildPathScope(id, projectScope, dependencyScopes); + } + + static ProjectScope projectScope(String id) { + return new DefaultProjectScope(id); + } + + private static class DefaultExtensibleEnum implements ExtensibleEnum { + + private final String id; + + DefaultExtensibleEnum(String id) { + this.id = Objects.requireNonNull(id); + } + + public String id() { + return id; + } + + @Override + public int hashCode() { + return id().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj != null && getClass() == obj.getClass() && id().equals(((DefaultExtensibleEnum) obj).id()); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + id() + "]"; + } + } + + private static class DefaultDependencyScope extends DefaultExtensibleEnum implements DependencyScope { + private final boolean transitive; + + DefaultDependencyScope(String id, boolean transitive) { + super(id); + this.transitive = transitive; + } + + @Override + public boolean isTransitive() { + return transitive; + } + } + + private static class DefaultBuildPathScope extends DefaultExtensibleEnum implements BuildPathScope { + private final ProjectScope projectScope; + private final Set dependencyScopes; + + DefaultBuildPathScope(String id, ProjectScope projectScope, DependencyScope... dependencyScopes) { + super(id); + this.projectScope = Objects.requireNonNull(projectScope); + this.dependencyScopes = + Collections.unmodifiableSet(new HashSet<>(Arrays.asList(Objects.requireNonNull(dependencyScopes)))); + } + + @Override + public ProjectScope projectScope() { + return projectScope; + } + + @Override + public Set getDependencyScopes() { + return dependencyScopes; + } + } + + private static class DefaultProjectScope extends DefaultExtensibleEnum implements ProjectScope { + + DefaultProjectScope(String id) { + super(id); + } + } + + private static class DefaultLanguage extends DefaultExtensibleEnum implements Language { + + DefaultLanguage(String id) { + super(id); + } + } +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java index 9c228da08f77..0fc459287b57 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Language.java @@ -20,8 +20,8 @@ import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; -import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.annotations.Nullable; + +import static org.apache.maven.api.ExtensibleEnums.language; /** * Language. @@ -33,74 +33,15 @@ */ @Experimental @Immutable -public interface Language { +@SuppressWarnings("checkstyle:InterfaceIsType") +public interface Language extends ExtensibleEnum { + /** * The "none" language. It is not versioned, family is same to itself, and compatible with itself only. * In turn, every {@link Language} implementation must be compatible with {@code NONE} language. */ - Language NONE = new Language() { - @Override - public String id() { - return "none"; - } - - @Override - public Language family() { - return this; - } - - @Override - public Version version() { - return null; - } - - @Override - public boolean isCompatibleWith(Language language) { - return this == language; - } - }; + Language NONE = language("none"); // TODO: this should be moved out from here to Java Support (builtin into core) - Language JAVA_FAMILY = new Language() { - @Override - public String id() { - return "java"; - } - - @Override - public Language family() { - return this; - } - - @Override - public Version version() { - return null; - } - - public boolean isCompatibleWith(Language language) { - Language family = language.family(); - return this == family || NONE == family; - } - }; - - @Nonnull - String id(); - - @Nonnull - Language family(); - - @Nullable - Version version(); - - /** - * Returns {@code true} if this language is compatible with provided language. - * For example "Java 8" is compatible with "Java 11", but other way is not true. - *

          - * Important note: every implementation must return {@code true} if passed in language is {@link #NONE}. - *

          - * By default, every language is compatible with itself and {@link #NONE} language. Override if needed. - */ - default boolean isCompatibleWith(Language language) { - return this == language || NONE == language.family(); - } + Language JAVA_FAMILY = language("java"); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java index 94fddc0e8191..ede4c46b073f 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Packaging.java @@ -29,7 +29,7 @@ */ @Experimental @Immutable -public interface Packaging { +public interface Packaging extends ExtensibleEnum { /** * The packaging id. */ diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ProjectScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ProjectScope.java index 6fc06eeac376..e663e61463a0 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/ProjectScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ProjectScope.java @@ -20,7 +20,8 @@ import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; -import org.apache.maven.api.annotations.Nonnull; + +import static org.apache.maven.api.ExtensibleEnums.projectScope; /** * Project scope. @@ -32,45 +33,16 @@ */ @Experimental @Immutable -@SuppressWarnings("checkstyle:magicnumber") -public interface ProjectScope extends Comparable { - @Nonnull - String id(); - - int ordinal(); - - @Override - default int compareTo(ProjectScope o) { - return this.ordinal() - o.ordinal(); - } +@SuppressWarnings("checkstyle:InterfaceIsType") +public interface ProjectScope extends ExtensibleEnum { /** * Main scope. */ - ProjectScope MAIN = new ProjectScope() { - @Override - public String id() { - return "main"; - } - - @Override - public int ordinal() { - return 10; - } - }; + ProjectScope MAIN = projectScope("main"); /** * Test scope. */ - ProjectScope TEST = new ProjectScope() { - @Override - public String id() { - return "test"; - } - - @Override - public int ordinal() { - return 20; - } - }; + ProjectScope TEST = projectScope("test"); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index cd9dd024c7b7..4a5089350963 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -31,6 +31,7 @@ import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.annotations.ThreadSafe; import org.apache.maven.api.model.Repository; +import org.apache.maven.api.services.BuildPathScopeRegistry; import org.apache.maven.api.services.DependencyCoordinateFactory; import org.apache.maven.api.settings.Settings; @@ -501,4 +502,17 @@ Artifact createArtifact( */ @Nonnull VersionConstraint parseVersionConstraint(@Nonnull String versionConstraint); + + Type requireType(String id); + + Language requireLanguage(String id); + + Packaging requirePackaging(String id); + + ProjectScope requireProjectScope(String id); + + DependencyScope requireDependencyScope(String id); + + BuildPathScope requireBuildPathScope(String id); + } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java index 862049facf6e..003459926865 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java @@ -40,7 +40,7 @@ */ @Experimental @Immutable -public interface Type { +public interface Type extends ExtensibleEnum { /** * Returns the dependency type id. * The id uniquely identifies this dependency type. @@ -48,7 +48,7 @@ public interface Type { * @return the id of this type, never {@code null}. */ @Nonnull - String getId(); + String id(); /** * Returns the dependency type language. diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuildPathScopeRegistry.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuildPathScopeRegistry.java new file mode 100644 index 000000000000..c3ff0c223ff2 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuildPathScopeRegistry.java @@ -0,0 +1,23 @@ +/* + * 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.services; + +import org.apache.maven.api.BuildPathScope; + +public interface BuildPathScopeRegistry extends ExtensibleEnumRegistry {} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java index 6db92dbe652a..34483be0de67 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java @@ -89,7 +89,7 @@ static DependencyCoordinateFactoryRequest build(@Nonnull Session session, @Nonnu .version(dependency.getVersion().asString()) .classifier(dependency.getClassifier()) .extension(dependency.getExtension()) - .type(dependency.getType().getId()) + .type(dependency.getType().id()) .scope(dependency.getScope().id()) .optional(dependency.isOptional()) .build(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyScopeRegistry.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyScopeRegistry.java new file mode 100644 index 000000000000..1b3df452a928 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyScopeRegistry.java @@ -0,0 +1,23 @@ +/* + * 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.services; + +import org.apache.maven.api.DependencyScope; + +public interface DependencyScopeRegistry extends ExtensibleEnumRegistry {} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ExtensibleEnumRegistry.java similarity index 75% rename from api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageManager.java rename to api/maven-api-core/src/main/java/org/apache/maven/api/services/ExtensibleEnumRegistry.java index c322407be744..e51cc9941ce4 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageManager.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ExtensibleEnumRegistry.java @@ -20,15 +20,15 @@ import java.util.Optional; -import org.apache.maven.api.Language; +import org.apache.maven.api.ExtensibleEnum; import org.apache.maven.api.Service; import org.apache.maven.api.annotations.Nonnull; -public interface LanguageManager extends Service { +public interface ExtensibleEnumRegistry extends Service { @Nonnull - Optional lookupLanguageFamily(String id); + Optional lookup(String id); - default Language requireLanguageFamily(String id) { - return lookupLanguageFamily(id).orElseThrow(() -> new IllegalArgumentException("Unknown language")); + default T require(String id) { + return lookup(id).orElseThrow(() -> new IllegalArgumentException("Unknown extensible enum value " + id)); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLanguageManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageRegistry.java similarity index 51% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLanguageManager.java rename to api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageRegistry.java index c120eb83c506..d2f0f0933157 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLanguageManager.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LanguageRegistry.java @@ -16,32 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.maven.internal.impl; - -import javax.inject.Named; -import javax.inject.Singleton; - -import java.util.Objects; -import java.util.Optional; +package org.apache.maven.api.services; import org.apache.maven.api.Language; -import org.apache.maven.api.services.LanguageManager; -/** - * TODO: this is session scoped as SPI can contribute. - */ -@Named -@Singleton -public class DefaultLanguageManager implements LanguageManager { - @Override - public Optional lookupLanguageFamily(String id) { - if (Objects.equals(Language.NONE.id(), id)) { - return Optional.of(Language.NONE); - } - // TODO: this is now just a shortcut; elaborate this, probably with some SPI LanguageSupport - if (Objects.equals(Language.JAVA_FAMILY.id(), id)) { - return Optional.of(Language.JAVA_FAMILY); - } - return Optional.empty(); - } -} +public interface LanguageRegistry extends ExtensibleEnumRegistry {} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingRegistry.java similarity index 69% rename from api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingManager.java rename to api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingRegistry.java index 07568b4f644d..e114e2664058 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingManager.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PackagingRegistry.java @@ -18,17 +18,6 @@ */ package org.apache.maven.api.services; -import java.util.Optional; - import org.apache.maven.api.Packaging; -import org.apache.maven.api.Service; -import org.apache.maven.api.annotations.Nonnull; - -public interface PackagingManager extends Service { - @Nonnull - Optional lookupPackaging(String id); - default Packaging requirePackaging(String id) { - return lookupPackaging(id).orElseThrow(() -> new IllegalArgumentException("Unknown packaging")); - } -} +public interface PackagingRegistry extends ExtensibleEnumRegistry {} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectScopeRegistry.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectScopeRegistry.java new file mode 100644 index 000000000000..a3b4f24a5d58 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectScopeRegistry.java @@ -0,0 +1,26 @@ +/* + * 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.services; + +import org.apache.maven.api.ProjectScope; + +/** + * Manager for {@link ProjectScope}. + */ +public interface ProjectScopeRegistry extends ExtensibleEnumRegistry {} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java index c484df40f5db..ca4c40d48a19 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java @@ -18,7 +18,6 @@ */ package org.apache.maven.api.services; -import org.apache.maven.api.Service; import org.apache.maven.api.Type; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; @@ -29,7 +28,7 @@ * @since 4.0.0 */ @Experimental -public interface TypeRegistry extends Service { +public interface TypeRegistry extends ExtensibleEnumRegistry { /** * Obtain the {@link Type} from the specified {@code id}. @@ -40,5 +39,5 @@ public interface TypeRegistry extends Service { * @return the type */ @Nonnull - Type getType(@Nonnull String id); + Type require(@Nonnull String id); } diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/BuildPathScopeProvider.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/BuildPathScopeProvider.java new file mode 100644 index 000000000000..3e8a54652178 --- /dev/null +++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/BuildPathScopeProvider.java @@ -0,0 +1,23 @@ +/* + * 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.spi; + +import org.apache.maven.api.BuildPathScope; + +public interface BuildPathScopeProvider extends ExtensibleEnumProvider {} diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/DependencyScopeProvider.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/DependencyScopeProvider.java new file mode 100644 index 000000000000..a7ed7e6568ba --- /dev/null +++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/DependencyScopeProvider.java @@ -0,0 +1,23 @@ +/* + * 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.spi; + +import org.apache.maven.api.DependencyScope; + +public interface DependencyScopeProvider extends ExtensibleEnumProvider {} diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ExtensibleEnumProvider.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ExtensibleEnumProvider.java new file mode 100644 index 000000000000..514651088ac3 --- /dev/null +++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ExtensibleEnumProvider.java @@ -0,0 +1,28 @@ +/* + * 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.spi; + +import java.util.Collection; + +import org.apache.maven.api.ExtensibleEnum; + +public interface ExtensibleEnumProvider { + + Collection provides(); +} diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/LanguageProvider.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/LanguageProvider.java new file mode 100644 index 000000000000..9757d04f2005 --- /dev/null +++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/LanguageProvider.java @@ -0,0 +1,23 @@ +/* + * 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.spi; + +import org.apache.maven.api.Language; + +public interface LanguageProvider extends ExtensibleEnumProvider {} diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/PackagingProvider.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/PackagingProvider.java new file mode 100644 index 000000000000..bfcf3a219100 --- /dev/null +++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/PackagingProvider.java @@ -0,0 +1,23 @@ +/* + * 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.spi; + +import org.apache.maven.api.Packaging; + +public interface PackagingProvider extends ExtensibleEnumProvider {} diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ProjectScopeProvider.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ProjectScopeProvider.java new file mode 100644 index 000000000000..c4a9a1f992a3 --- /dev/null +++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ProjectScopeProvider.java @@ -0,0 +1,23 @@ +/* + * 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.spi; + +import org.apache.maven.api.ProjectScope; + +public interface ProjectScopeProvider extends ExtensibleEnumProvider {} diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java index f25856333bb6..3a0c1a234f8f 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java @@ -62,7 +62,7 @@ public void onEvent(Object event) { public ArtifactHandler getArtifactHandler(String id) { return allHandlers.computeIfAbsent(id, k -> { - Type type = typeRegistry.getType(id); + Type type = typeRegistry.require(id); return new DefaultArtifactHandler( id, type.getExtension(), diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java index b5f3f9c61437..daa86e7426ec 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java +++ b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java @@ -35,13 +35,13 @@ class TypeRegistryAdapter implements ArtifactTypeRegistry { @Override public ArtifactType get(String typeId) { - Type type = typeRegistry.getType(typeId); + Type type = typeRegistry.require(typeId); if (type instanceof ArtifactType) { return (ArtifactType) type; } if (type != null) { return new DefaultType( - type.getId(), + type.id(), type.getLanguage(), type.getExtension(), type.getClassifier(), diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index ce90e19be732..bc3702028ada 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -518,4 +518,34 @@ public Version resolveVersion(ArtifactCoordinate artifact) { public List resolveVersionRange(ArtifactCoordinate artifact) { return getService(VersionRangeResolver.class).resolve(this, artifact).getVersions(); } + + @Override + public Type requireType(String id) { + return getService(TypeRegistry.class).require(id); + } + + @Override + public Language requireLanguage(String id) { + return getService(LanguageRegistry.class).require(id); + } + + @Override + public Packaging requirePackaging(String id) { + return getService(PackagingRegistry.class).require(id); + } + + @Override + public ProjectScope requireProjectScope(String id) { + return getService(ProjectScopeRegistry.class).require(id); + } + + @Override + public DependencyScope requireDependencyScope(String id) { + return getService(DependencyScopeRegistry.class).require(id); + } + + @Override + public BuildPathScope requireBuildPathScope(String id) { + return getService(BuildPathScopeRegistry.class).require(id); + } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java index 3f2f06893ebf..c8b0d6b3c84d 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java @@ -102,7 +102,7 @@ public Type getType() { String type = dependency .getArtifact() .getProperty(ArtifactProperties.TYPE, dependency.getArtifact().getExtension()); - return session.getService(TypeRegistry.class).getType(type); + return session.requireType(type); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java index 54121e8da6d8..1095e4b433a7 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java @@ -73,7 +73,7 @@ public Type getType() { String type = dependency .getArtifact() .getProperty(ArtifactProperties.TYPE, dependency.getArtifact().getExtension()); - return session.getService(TypeRegistry.class).getType(type); + return session.requireType(type); } @Nonnull diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingRegistry.java similarity index 85% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java rename to maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingRegistry.java index 8364b1192670..9e5a05346b0c 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingManager.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingRegistry.java @@ -27,7 +27,7 @@ import org.apache.maven.api.Packaging; import org.apache.maven.api.Type; -import org.apache.maven.api.services.PackagingManager; +import org.apache.maven.api.services.PackagingRegistry; import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.lifecycle.mapping.LifecycleMapping; @@ -36,24 +36,24 @@ */ @Named @Singleton -public class DefaultPackagingManager implements PackagingManager { +public class DefaultPackagingRegistry implements PackagingRegistry { private final Map lifecycleMappings; private final TypeRegistry typeRegistry; @Inject - public DefaultPackagingManager(Map lifecycleMappings, TypeRegistry typeRegistry) { + public DefaultPackagingRegistry(Map lifecycleMappings, TypeRegistry typeRegistry) { this.lifecycleMappings = lifecycleMappings; this.typeRegistry = typeRegistry; } @Override - public Optional lookupPackaging(String id) { + public Optional lookup(String id) { LifecycleMapping lifecycleMapping = lifecycleMappings.get(id); if (lifecycleMapping == null) { return Optional.empty(); } - Type type = typeRegistry.getType(id); + Type type = typeRegistry.require(id); if (type == null) { return Optional.empty(); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java index bd018ab05158..f962b830920e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java @@ -27,7 +27,7 @@ import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.model.DependencyManagement; import org.apache.maven.api.model.Model; -import org.apache.maven.api.services.PackagingManager; +import org.apache.maven.api.services.PackagingRegistry; import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.project.MavenProject; import org.apache.maven.project.artifact.ProjectArtifact; @@ -44,7 +44,7 @@ public class DefaultProject implements Project { public DefaultProject(InternalSession session, MavenProject project) { this.session = session; this.project = project; - this.packaging = session.getService(PackagingManager.class).requirePackaging(project.getPackaging()); + this.packaging = session.requirePackaging(project.getPackaging()); } public InternalSession getSession() { @@ -178,7 +178,7 @@ public String getExtension() { @Override public Type getType() { String type = dependency.getType(); - return session.getService(TypeRegistry.class).getType(type); + return session.requireType(type); } @Nonnull diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java index 9b272c31a4b4..b6042784d1d2 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java @@ -57,10 +57,15 @@ public DefaultType( } @Override - public String getId() { + public String id() { return dependencyProperties.asMap().get(ArtifactProperties.TYPE); } + @Override + public String getId() { + return id(); + } + @Override public Language getLanguage() { return language; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java index 41174da40f5d..76c575c0c413 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java @@ -24,12 +24,13 @@ import java.util.ArrayList; import java.util.Map; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Type; import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.services.LanguageManager; +import org.apache.maven.api.services.LanguageRegistry; import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.handler.manager.LegacyArtifactHandlerManager; @@ -43,7 +44,7 @@ public class DefaultTypeRegistry extends AbstractEventSpy implements TypeRegistry { private final Map types; - private final LanguageManager languageManager; + private final LanguageRegistry languageRegistry; private final ConcurrentHashMap usedTypes; @@ -53,9 +54,9 @@ public class DefaultTypeRegistry extends AbstractEventSpy implements TypeRegistr @Inject public DefaultTypeRegistry( - Map types, LanguageManager languageManager, LegacyArtifactHandlerManager manager) { + Map types, LanguageRegistry languageRegistry, LegacyArtifactHandlerManager manager) { this.types = nonNull(types, "types"); - this.languageManager = nonNull(languageManager, "languageManager"); + this.languageRegistry = nonNull(languageRegistry, "languageRegistry"); this.usedTypes = new ConcurrentHashMap<>(); this.legacyTypes = new ConcurrentHashMap<>(); this.manager = nonNull(manager, "artifactHandlerManager"); @@ -72,9 +73,14 @@ public void onEvent(Object event) { } } + @Override + public Optional lookup(String id) { + return Optional.of(require(id)); + } + @Override @Nonnull - public Type getType(String id) { + public Type require(String id) { nonNull(id, "id"); return usedTypes.computeIfAbsent(id, i -> { Type type = types.get(id); @@ -92,7 +98,7 @@ public Type getType(String id) { } return new DefaultType( id, - languageManager.requireLanguageFamily(handler.getLanguage()), + languageRegistry.require(handler.getLanguage()), handler.getExtension(), handler.getClassifier(), new DefaultDependencyProperties(flags)); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java new file mode 100644 index 000000000000..1ef4dc912b79 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java @@ -0,0 +1,115 @@ +/* + * 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.internal.impl; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.maven.SessionScoped; +import org.apache.maven.api.*; +import org.apache.maven.api.services.*; +import org.apache.maven.api.spi.*; + +public class ExtensibleEnumRegistries { + + @Named + @SessionScoped + public static class DefaultBuildPathScopeRegistry + extends DefaultExtensibleEnumRegistry + implements BuildPathScopeRegistry { + + @Inject + public DefaultBuildPathScopeRegistry(List providers) { + super( + providers, + BuildPathScope.MAIN_COMPILE, + BuildPathScope.MAIN_RUNTIME, + BuildPathScope.TEST_COMPILE, + BuildPathScope.TEST_RUNTIME); + } + } + + @Named + @SessionScoped + public static class DefaultDependencyScopeRegistry + extends DefaultExtensibleEnumRegistry + implements DependencyScopeRegistry { + + @Inject + public DefaultDependencyScopeRegistry(List providers) { + super( + providers, + DependencyScope.NONE, + DependencyScope.COMPILE_ONLY, + DependencyScope.COMPILE, + DependencyScope.RUNTIME, + DependencyScope.PROVIDED, + DependencyScope.TEST_ONLY, + DependencyScope.TEST, + DependencyScope.TEST_RUNTIME, + DependencyScope.SYSTEM); + } + } + + @Named + @SessionScoped + public static class DefaultProjectScopeRegistry + extends DefaultExtensibleEnumRegistry implements ProjectScopeRegistry { + + @Inject + public DefaultProjectScopeRegistry(List providers) { + super(providers, ProjectScope.MAIN, ProjectScope.TEST); + } + } + + @Named + @Singleton + public static class DefaultLanguageRegistry extends DefaultExtensibleEnumRegistry + implements LanguageRegistry { + + @Inject + public DefaultLanguageRegistry(List providers) { + super(providers, Language.NONE, Language.JAVA_FAMILY); + } + } + + static class DefaultExtensibleEnumRegistry> + implements ExtensibleEnumRegistry { + + private final Map values; + + DefaultExtensibleEnumRegistry(List

          providers, T... builtinValues) { + values = Stream.concat( + Stream.of(builtinValues), providers.stream().flatMap(p -> p.provides().stream())) + .collect(Collectors.toMap(t -> t.id(), t -> t)); + } + + @Override + public Optional lookup(String id) { + return Optional.ofNullable(values.get(id)); + } + } +} diff --git a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java index 8fb0163fbdab..dd6beba8aff8 100644 --- a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java +++ b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java @@ -150,8 +150,7 @@ protected MavenSession createMavenSession(File pom, Properties executionProperti initRepoSession(configuration); DefaultSessionFactory defaultSessionFactory = - new DefaultSessionFactory(mock(RepositorySystem.class), - null, new DefaultLookup(container), null); + new DefaultSessionFactory(mock(RepositorySystem.class), null, new DefaultLookup(container), null); MavenSession session = new MavenSession( getContainer(), configuration.getRepositorySession(), request, new DefaultMavenExecutionResult()); From cf087274a353ded7ac92beef45488bc2e8ebcff3 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 15:12:36 +0100 Subject: [PATCH 20/31] Use the new scopes --- .../org/apache/maven/api/BuildPathScope.java | 2 +- .../java/org/apache/maven/api/Dependency.java | 2 +- .../maven/api/DependencyCoordinate.java | 2 +- .../org/apache/maven/api/ExtensibleEnums.java | 2 +- .../org/apache/maven/api/ResolutionScope.java | 97 ------------------- .../main/java/org/apache/maven/api/Scope.java | 66 ------------- .../java/org/apache/maven/api/Session.java | 8 +- .../api/services/DependencyResolver.java | 14 ++- .../services/DependencyResolverRequest.java | 26 ++--- .../api/services/ExtensibleEnumRegistry.java | 2 +- .../maven/internal/impl/AbstractSession.java | 4 +- .../internal/impl/DefaultDependency.java | 7 +- .../impl/DefaultDependencyCoordinate.java | 5 +- .../impl/DefaultDependencyResolver.java | 22 ++--- .../impl/DefaultPackagingRegistry.java | 2 +- .../maven/internal/impl/DefaultProject.java | 6 +- .../apache/maven/internal/impl/TestApi.java | 10 +- 17 files changed, 47 insertions(+), 230 deletions(-) delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/ResolutionScope.java delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java index 3142ee39bd71..47dbd73c70c2 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java @@ -42,7 +42,7 @@ public interface BuildPathScope extends ExtensibleEnum { ProjectScope projectScope(); @Nonnull - Set getDependencyScopes(); + Set dependencyScopes(); BuildPathScope MAIN_COMPILE = buildPathScope( "main-compile", diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java index efad1415adf8..f0617a0a1e39 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java @@ -39,7 +39,7 @@ public interface Dependency extends Artifact { DependencyProperties getDependencyProperties(); @Nonnull - Scope getScope(); + DependencyScope getScope(); boolean isOptional(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinate.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinate.java index 7ba4bd1ec75e..c0295bfaa0e4 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinate.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinate.java @@ -41,7 +41,7 @@ public interface DependencyCoordinate extends ArtifactCoordinate { Type getType(); @Nonnull - Scope getScope(); + DependencyScope getScope(); @Nullable Boolean getOptional(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java index 60f394b30b86..4035842b6caf 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java @@ -97,7 +97,7 @@ public ProjectScope projectScope() { } @Override - public Set getDependencyScopes() { + public Set dependencyScopes() { return dependencyScopes; } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ResolutionScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ResolutionScope.java deleted file mode 100644 index 7d003694d633..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/ResolutionScope.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.maven.api.annotations.Experimental; - -/** - * Dependencies resolution scopes available before - * mojo execution. - * - * Important note: The {@code id} values of this enum correspond to constants of - * {@code org.apache.maven.artifact.Artifact} class and MUST BE KEPT IN SYNC. - * - * @since 4.0.0 - */ -@Experimental -public enum ResolutionScope { - /** - * compile resolution scope - * = compile-only + compile + provided dependencies - */ - PROJECT_COMPILE("project-compile", Scope.EMPTY, Scope.COMPILE_ONLY, Scope.COMPILE, Scope.PROVIDED), - /** - * runtime resolution scope - * = compile + runtime dependencies - */ - PROJECT_RUNTIME("project-runtime", Scope.EMPTY, Scope.COMPILE, Scope.RUNTIME), - /** - * test-compile resolution scope - * = compile-only + compile + provided + test-compile-only + test - * dependencies - */ - TEST_COMPILE( - "test-compile", - Scope.EMPTY, - Scope.COMPILE_ONLY, - Scope.COMPILE, - Scope.PROVIDED, - Scope.TEST_COMPILE_ONLY, - Scope.TEST), - /** - * test resolution scope - * = compile + runtime + provided + test + test-runtime - * dependencies - */ - TEST_RUNTIME( - "test-runtime", Scope.EMPTY, Scope.COMPILE, Scope.RUNTIME, Scope.PROVIDED, Scope.TEST, Scope.TEST_RUNTIME); - - private static final Map VALUES = - Stream.of(ResolutionScope.values()).collect(Collectors.toMap(ResolutionScope::id, s -> s)); - - public static ResolutionScope fromString(String id) { - return Optional.ofNullable(VALUES.get(id)) - .orElseThrow(() -> new IllegalArgumentException("Unknown resolution scope " + id)); - } - - private final String id; - private final Set scopes; - - ResolutionScope(String id, Scope... scopes) { - this.id = id; - this.scopes = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(scopes))); - } - - public String id() { - return this.id; - } - - public Set scopes() { - return scopes; - } -} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java deleted file mode 100644 index 624293c1e92d..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.util.HashMap; -import java.util.Map; - -import org.apache.maven.api.annotations.Experimental; - -/** - * Scope for a dependency - * - * @since 4.0.0 - */ -@Experimental -public enum Scope { - EMPTY(""), - COMPILE_ONLY("compile-only"), - COMPILE("compile"), - RUNTIME("runtime"), - PROVIDED("provided"), - TEST_COMPILE_ONLY("test-compile-only"), - TEST("test"), - TEST_RUNTIME("test-runtime"), - IMPORT("import"); // TODO: v4: remove import scope somehow - - private final String id; - - private static final Map SCOPES; - - static { - Map scopes = new HashMap<>(); - for (Scope s : Scope.values()) { - scopes.put(s.id, s); - } - SCOPES = scopes; - } - - Scope(String id) { - this.id = id; - } - - public String id() { - return this.id; - } - - public static Scope get(String scope) { - return SCOPES.get(scope); - } -} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index 4a5089350963..bc6105f99b65 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -31,7 +31,6 @@ import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.annotations.ThreadSafe; import org.apache.maven.api.model.Repository; -import org.apache.maven.api.services.BuildPathScopeRegistry; import org.apache.maven.api.services.DependencyCoordinateFactory; import org.apache.maven.api.settings.Settings; @@ -428,11 +427,11 @@ Artifact createArtifact( /** * Shortcut for {@code getService(DependencyResolver.class).flatten(...)}. * - * @see org.apache.maven.api.services.DependencyResolver#flatten(Session, Node, ResolutionScope) + * @see org.apache.maven.api.services.DependencyResolver#flatten(Session, Node, BuildPathScope) * @throws org.apache.maven.api.services.DependencyResolverException if the dependency flattening failed */ @Nonnull - List flattenDependencies(@Nonnull Node node, @Nonnull ResolutionScope scope); + List flattenDependencies(@Nonnull Node node, @Nonnull BuildPathScope scope); @Nonnull List resolveDependencies(@Nonnull DependencyCoordinate dependencyCoordinate); @@ -441,7 +440,7 @@ Artifact createArtifact( List resolveDependencies(@Nonnull List dependencyCoordinates); @Nonnull - List resolveDependencies(@Nonnull Project project, @Nonnull ResolutionScope scope); + List resolveDependencies(@Nonnull Project project, @Nonnull BuildPathScope scope); /** * Resolves an artifact's meta version (if any) to a concrete version. For example, resolves "1.0-SNAPSHOT" @@ -514,5 +513,4 @@ Artifact createArtifact( DependencyScope requireDependencyScope(String id); BuildPathScope requireBuildPathScope(String id); - } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java index 3da46b1f5bde..440b1b3f023a 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java @@ -20,10 +20,10 @@ import java.util.List; +import org.apache.maven.api.BuildPathScope; import org.apache.maven.api.DependencyCoordinate; import org.apache.maven.api.Node; import org.apache.maven.api.Project; -import org.apache.maven.api.ResolutionScope; import org.apache.maven.api.Service; import org.apache.maven.api.Session; import org.apache.maven.api.annotations.Experimental; @@ -35,7 +35,7 @@ @Experimental public interface DependencyResolver extends Service { - List flatten(Session session, Node node, ResolutionScope scope) throws DependencyResolverException; + List flatten(Session session, Node node, BuildPathScope scope) throws DependencyResolverException; /** * This method collects, flattens and resolves the dependencies. @@ -47,7 +47,7 @@ public interface DependencyResolver extends Service { * @throws ArtifactResolverException * * @see DependencyCollector#collect(DependencyCollectorRequest) - * @see #flatten(Session, Node, ResolutionScope) + * @see #flatten(Session, Node, BuildPathScope) * @see ArtifactResolver#resolve(ArtifactResolverRequest) */ DependencyResolverResult resolve(DependencyResolverRequest request) @@ -60,7 +60,7 @@ default DependencyResolverResult resolve(@Nonnull Session session, @Nonnull Proj @Nonnull default DependencyResolverResult resolve( - @Nonnull Session session, @Nonnull Project project, @Nonnull ResolutionScope scope) { + @Nonnull Session session, @Nonnull Project project, @Nonnull BuildPathScope scope) { return resolve(DependencyResolverRequest.build(session, project, scope)); } @@ -71,7 +71,7 @@ default DependencyResolverResult resolve(@Nonnull Session session, @Nonnull Depe @Nonnull default DependencyResolverResult resolve( - @Nonnull Session session, @Nonnull DependencyCoordinate dependency, @Nonnull ResolutionScope scope) { + @Nonnull Session session, @Nonnull DependencyCoordinate dependency, @Nonnull BuildPathScope scope) { return resolve(DependencyResolverRequest.build(session, dependency, scope)); } @@ -83,9 +83,7 @@ default DependencyResolverResult resolve( @Nonnull default DependencyResolverResult resolve( - @Nonnull Session session, - @Nonnull List dependencies, - @Nonnull ResolutionScope scope) { + @Nonnull Session session, @Nonnull List dependencies, @Nonnull BuildPathScope scope) { return resolve(DependencyResolverRequest.build(session, dependencies, scope)); } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java index 0519ececf1d7..454766ec83c3 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java @@ -22,9 +22,9 @@ import java.util.List; import org.apache.maven.api.Artifact; +import org.apache.maven.api.BuildPathScope; import org.apache.maven.api.DependencyCoordinate; import org.apache.maven.api.Project; -import org.apache.maven.api.ResolutionScope; import org.apache.maven.api.Session; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; @@ -35,7 +35,7 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest { @Nonnull - ResolutionScope getResolutionScope(); + BuildPathScope getResolutionScope(); @Nonnull static DependencyResolverRequestBuilder builder() { @@ -44,11 +44,11 @@ static DependencyResolverRequestBuilder builder() { @Nonnull static DependencyResolverRequest build(Session session, Project project) { - return build(session, project, ResolutionScope.PROJECT_RUNTIME); + return build(session, project, BuildPathScope.MAIN_RUNTIME); } @Nonnull - static DependencyResolverRequest build(Session session, Project project, ResolutionScope scope) { + static DependencyResolverRequest build(Session session, Project project, BuildPathScope scope) { return new DependencyResolverRequestBuilder() .session(session) .project(project) @@ -58,11 +58,11 @@ static DependencyResolverRequest build(Session session, Project project, Resolut @Nonnull static DependencyResolverRequest build(Session session, DependencyCoordinate dependency) { - return build(session, dependency, ResolutionScope.PROJECT_RUNTIME); + return build(session, dependency, BuildPathScope.MAIN_RUNTIME); } @Nonnull - static DependencyResolverRequest build(Session session, DependencyCoordinate dependency, ResolutionScope scope) { + static DependencyResolverRequest build(Session session, DependencyCoordinate dependency, BuildPathScope scope) { return new DependencyResolverRequestBuilder() .session(session) .dependency(dependency) @@ -72,12 +72,12 @@ static DependencyResolverRequest build(Session session, DependencyCoordinate dep @Nonnull static DependencyResolverRequest build(Session session, List dependencies) { - return build(session, dependencies, ResolutionScope.PROJECT_RUNTIME); + return build(session, dependencies, BuildPathScope.MAIN_RUNTIME); } @Nonnull static DependencyResolverRequest build( - Session session, List dependencies, ResolutionScope scope) { + Session session, List dependencies, BuildPathScope scope) { return new DependencyResolverRequestBuilder() .session(session) .dependencies(dependencies) @@ -87,7 +87,7 @@ static DependencyResolverRequest build( @NotThreadSafe class DependencyResolverRequestBuilder extends DependencyCollectorRequestBuilder { - ResolutionScope resolutionScope; + BuildPathScope resolutionScope; @Nonnull @Override @@ -154,7 +154,7 @@ public DependencyResolverRequestBuilder verbose(boolean verbose) { } @Nonnull - public DependencyResolverRequestBuilder resolutionScope(@Nonnull ResolutionScope resolutionScope) { + public DependencyResolverRequestBuilder resolutionScope(@Nonnull BuildPathScope resolutionScope) { this.resolutionScope = resolutionScope; return this; } @@ -167,7 +167,7 @@ public DependencyResolverRequest build() { static class DefaultDependencyResolverRequest extends DefaultDependencyCollectorRequest implements DependencyResolverRequest { - private final ResolutionScope resolutionScope; + private final BuildPathScope resolutionScope; DefaultDependencyResolverRequest( Session session, @@ -177,7 +177,7 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector Collection dependencies, Collection managedDependencies, boolean verbose, - ResolutionScope resolutionScope) { + BuildPathScope resolutionScope) { super(session, project, rootArtifact, root, dependencies, managedDependencies, verbose); this.resolutionScope = nonNull(resolutionScope, "resolutionScope cannot be null"); if (verbose) { @@ -187,7 +187,7 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector @Nonnull @Override - public ResolutionScope getResolutionScope() { + public BuildPathScope getResolutionScope() { return resolutionScope; } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ExtensibleEnumRegistry.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ExtensibleEnumRegistry.java index e51cc9941ce4..3a5673c583e2 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ExtensibleEnumRegistry.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ExtensibleEnumRegistry.java @@ -29,6 +29,6 @@ public interface ExtensibleEnumRegistry extends Servic Optional lookup(String id); default T require(String id) { - return lookup(id).orElseThrow(() -> new IllegalArgumentException("Unknown extensible enum value " + id)); + return lookup(id).orElseThrow(() -> new IllegalArgumentException("Unknown extensible enum value '" + id + "'")); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index bc3702028ada..18e91be78414 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -462,7 +462,7 @@ public Node collectDependencies(@Nonnull DependencyCoordinate dependency) { @Nonnull @Override - public List flattenDependencies(@Nonnull Node node, @Nonnull ResolutionScope scope) { + public List flattenDependencies(@Nonnull Node node, @Nonnull BuildPathScope scope) { return getService(DependencyResolver.class).flatten(this, node, scope); } @@ -477,7 +477,7 @@ public List resolveDependencies(List dependencies) { } @Override - public List resolveDependencies(Project project, ResolutionScope scope) { + public List resolveDependencies(Project project, BuildPathScope scope) { return getService(DependencyResolver.class) .resolve(this, project, scope) .getPaths(); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java index c8b0d6b3c84d..7c63b34279c2 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java @@ -24,12 +24,11 @@ import org.apache.maven.api.Dependency; import org.apache.maven.api.DependencyCoordinate; import org.apache.maven.api.DependencyProperties; -import org.apache.maven.api.Scope; +import org.apache.maven.api.DependencyScope; import org.apache.maven.api.Type; import org.apache.maven.api.Version; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; -import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.repository.internal.DefaultModelVersionParser; import org.eclipse.aether.artifact.ArtifactProperties; @@ -117,8 +116,8 @@ public boolean isSnapshot() { @Nonnull @Override - public Scope getScope() { - return Scope.get(dependency.getScope()); + public DependencyScope getScope() { + return session.requireDependencyScope(dependency.getScope()); } @Nullable diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java index 1095e4b433a7..c0420f5fbba4 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java @@ -23,7 +23,6 @@ import org.apache.maven.api.*; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; -import org.apache.maven.api.services.TypeRegistry; import org.eclipse.aether.artifact.ArtifactProperties; import static org.apache.maven.internal.impl.Utils.nonNull; @@ -78,8 +77,8 @@ public Type getType() { @Nonnull @Override - public Scope getScope() { - return Scope.get(dependency.getScope()); + public DependencyScope getScope() { + return session.requireDependencyScope(dependency.getScope()); } @Nullable diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java index c5ba1a32b02d..14bb73953403 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java @@ -33,14 +33,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.maven.api.Artifact; -import org.apache.maven.api.ArtifactCoordinate; -import org.apache.maven.api.Dependency; -import org.apache.maven.api.Node; -import org.apache.maven.api.Project; -import org.apache.maven.api.ResolutionScope; -import org.apache.maven.api.Scope; -import org.apache.maven.api.Session; +import org.apache.maven.api.*; import org.apache.maven.api.services.*; import org.apache.maven.lifecycle.LifecycleExecutionException; import org.apache.maven.lifecycle.internal.LifecycleDependencyResolver; @@ -58,7 +51,7 @@ public class DefaultDependencyResolver implements DependencyResolver { @Override - public List flatten(Session s, Node node, ResolutionScope scope) throws DependencyResolverException { + public List flatten(Session s, Node node, BuildPathScope scope) throws DependencyResolverException { InternalSession session = InternalSession.from(s); DependencyNode root = cast(AbstractNode.class, node, "node").getDependencyNode(); List dependencies = session.getRepositorySystem() @@ -67,8 +60,9 @@ public List flatten(Session s, Node node, ResolutionScope scope) throws De return map(dependencies, session::getNode); } - private static DependencyFilter getScopeDependencyFilter(ResolutionScope scope) { - Set scopes = scope.scopes().stream().map(Scope::id).collect(Collectors.toSet()); + private static DependencyFilter getScopeDependencyFilter(BuildPathScope scope) { + Set scopes = + scope.dependencyScopes().stream().map(DependencyScope::id).collect(Collectors.toSet()); return (n, p) -> { org.eclipse.aether.graph.Dependency d = n.getDependency(); return d == null || scopes.contains(d.getScope()); @@ -130,7 +124,7 @@ private Stream stream(DependencyNode node) { return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(this::stream)); } - private DependencyResolutionResult resolveDependencies(Session session, Project project, ResolutionScope scope) { + private DependencyResolutionResult resolveDependencies(Session session, Project project, BuildPathScope scope) { Collection toResolve = toScopes(scope); try { LifecycleDependencyResolver lifecycleDependencyResolver = @@ -151,8 +145,8 @@ private MavenProject getMavenProject(Project project) { return ((DefaultProject) project).getProject(); } - private Collection toScopes(ResolutionScope scope) { - return map(scope.scopes(), Scope::id); + private Collection toScopes(BuildPathScope scope) { + return map(scope.dependencyScopes(), DependencyScope::id); } static class DefaultDependencyResolverResult implements DependencyResolverResult { diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingRegistry.java index 9e5a05346b0c..2a5b8a63b53e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingRegistry.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPackagingRegistry.java @@ -53,7 +53,7 @@ public Optional lookup(String id) { if (lifecycleMapping == null) { return Optional.empty(); } - Type type = typeRegistry.require(id); + Type type = typeRegistry.lookup(id).orElse(null); if (type == null) { return Optional.empty(); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java index f962b830920e..e2f59668eca8 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java @@ -27,8 +27,6 @@ import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.model.DependencyManagement; import org.apache.maven.api.model.Model; -import org.apache.maven.api.services.PackagingRegistry; -import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.project.MavenProject; import org.apache.maven.project.artifact.ProjectArtifact; import org.eclipse.aether.util.artifact.ArtifactIdUtils; @@ -183,8 +181,8 @@ public Type getType() { @Nonnull @Override - public Scope getScope() { - return Scope.get(dependency.getScope()); + public DependencyScope getScope() { + return session.requireDependencyScope(dependency.getScope()); } @Override diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java index 8f2ec04eb984..9f165930708e 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java +++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java @@ -30,13 +30,7 @@ import java.util.Optional; import java.util.stream.Collectors; -import org.apache.maven.api.Artifact; -import org.apache.maven.api.ArtifactCoordinate; -import org.apache.maven.api.Dependency; -import org.apache.maven.api.Node; -import org.apache.maven.api.Project; -import org.apache.maven.api.ResolutionScope; -import org.apache.maven.api.Session; +import org.apache.maven.api.*; import org.apache.maven.api.services.DependencyResolver; import org.apache.maven.api.services.DependencyResolverResult; import org.apache.maven.api.services.ProjectBuilder; @@ -200,7 +194,7 @@ void testProjectDependencies() { assertNotNull(root); DependencyResolverResult result = - session.getService(DependencyResolver.class).resolve(session, project, ResolutionScope.PROJECT_RUNTIME); + session.getService(DependencyResolver.class).resolve(session, project, BuildPathScope.MAIN_RUNTIME); assertNotNull(result); List deps = new ArrayList<>(result.getDependencies().keySet()); List deps2 = result.getNodes().stream() From ff413ae6d95e5dd98ca5c5f498f433822b0ffea8 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 15:39:20 +0100 Subject: [PATCH 21/31] Fix UT --- .../src/main/java/org/apache/maven/api/BuildPathScope.java | 7 +++++-- .../main/java/org/apache/maven/api/DependencyScope.java | 5 +++++ .../maven/internal/impl/ExtensibleEnumRegistries.java | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java index 47dbd73c70c2..5cff60cf87d9 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java @@ -47,16 +47,18 @@ public interface BuildPathScope extends ExtensibleEnum { BuildPathScope MAIN_COMPILE = buildPathScope( "main-compile", ProjectScope.MAIN, + DependencyScope.EMPTY, DependencyScope.COMPILE_ONLY, DependencyScope.COMPILE, DependencyScope.PROVIDED); - BuildPathScope MAIN_RUNTIME = - buildPathScope("main-runtime", ProjectScope.MAIN, DependencyScope.COMPILE, DependencyScope.RUNTIME); + BuildPathScope MAIN_RUNTIME = buildPathScope( + "main-runtime", ProjectScope.MAIN, DependencyScope.EMPTY, DependencyScope.COMPILE, DependencyScope.RUNTIME); BuildPathScope TEST_COMPILE = buildPathScope( "test-compile", ProjectScope.TEST, + DependencyScope.EMPTY, DependencyScope.COMPILE, DependencyScope.PROVIDED, DependencyScope.TEST_ONLY, @@ -65,6 +67,7 @@ public interface BuildPathScope extends ExtensibleEnum { BuildPathScope TEST_RUNTIME = buildPathScope( "test-runtime", ProjectScope.TEST, + DependencyScope.EMPTY, DependencyScope.COMPILE, DependencyScope.RUNTIME, DependencyScope.PROVIDED, diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java index ab64575b8cda..f3d26aa0686f 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java @@ -43,6 +43,11 @@ public interface DependencyScope extends ExtensibleEnum { */ DependencyScope NONE = dependencyScope("none", false); + /** + * Empty scope. + */ + DependencyScope EMPTY = dependencyScope("", false); + /** * Compile only. */ diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java index 1ef4dc912b79..e6011bf6679e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java @@ -63,6 +63,7 @@ public DefaultDependencyScopeRegistry(List providers) { super( providers, DependencyScope.NONE, + DependencyScope.EMPTY, DependencyScope.COMPILE_ONLY, DependencyScope.COMPILE, DependencyScope.RUNTIME, From 56b6b5a9973be2fac4e9c9df8271f50f3c56163c Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 18:31:56 +0100 Subject: [PATCH 22/31] Remove DependencyProperties interface --- .../java/org/apache/maven/api/Dependency.java | 8 --- .../maven/api/DependencyProperties.java | 57 ---------------- .../main/java/org/apache/maven/api/Type.java | 16 +---- .../internal/aether/TypeRegistryAdapter.java | 3 +- .../internal/impl/DefaultDependency.java | 9 --- .../impl/DefaultDependencyProperties.java | 66 ------------------- .../maven/internal/impl/DefaultType.java | 41 +++++++----- .../internal/impl/DefaultTypeRegistry.java | 12 +--- .../internal/impl/types/BomTypeProvider.java | 3 +- .../internal/impl/types/EarTypeProvider.java | 9 +-- .../impl/types/EjbClientTypeProvider.java | 9 +-- .../internal/impl/types/EjbTypeProvider.java | 9 +-- .../internal/impl/types/JarTypeProvider.java | 9 +-- .../impl/types/JavaSourceTypeProvider.java | 3 +- .../impl/types/JavadocTypeProvider.java | 9 +-- .../impl/types/MavenPluginTypeProvider.java | 9 +-- .../internal/impl/types/ParTypeProvider.java | 9 +-- .../internal/impl/types/PomTypeProvider.java | 3 +- .../internal/impl/types/RarTypeProvider.java | 9 +-- .../impl/types/TestJarTypeProvider.java | 9 +-- .../internal/impl/types/WarTypeProvider.java | 9 +-- 21 files changed, 44 insertions(+), 267 deletions(-) delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java delete mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java index f0617a0a1e39..b64fffc0d5e0 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java @@ -30,14 +30,6 @@ public interface Dependency extends Artifact { @Nonnull Type getType(); - /** - * The dependency properties. - * - * @return the dependency properties, never {@code null} - */ - @Nonnull - DependencyProperties getDependencyProperties(); - @Nonnull DependencyScope getScope(); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java deleted file mode 100644 index ad52851cd458..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.util.Map; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.annotations.Immutable; -import org.apache.maven.api.annotations.Nonnull; - -/** - * Dependency properties supported by Maven Core. - * - * @since 4.0.0 - */ -@Experimental -@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. - */ - String FLAG_INCLUDES_DEPENDENCIES = "includesDependencies"; - - /** - * Boolean flag telling that dependency is meant to be part of build path. Value of this key should be parsed with - * {@link Boolean#parseBoolean(String)} to obtain value. - */ - String FLAG_BUILD_PATH_CONSTITUENT = "constitutesBuildPath"; - - /** - * Returns immutable "map view" of all the properties. - */ - @Nonnull - Map asMap(); - - /** - * Returns {@code true} if given flag is {@code true}. - */ - boolean checkFlag(@Nonnull String flag); -} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java index 003459926865..45a46fd1a1ca 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java @@ -81,9 +81,7 @@ public interface Type extends ExtensibleEnum { * * @return if the artifact should be added to the build path */ - default boolean isBuildPathConstituent() { - return getDependencyProperties().checkFlag(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT); - } + boolean isBuildPathConstituent(); /** * Specifies if the artifact already embeds its own dependencies. @@ -92,15 +90,5 @@ default boolean isBuildPathConstituent() { * * @return if the artifact's dependencies are included in the artifact */ - default boolean isIncludesDependencies() { - return getDependencyProperties().checkFlag(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); - } - - /** - * Gets the default properties associated with this type. - * - * @return the default properties, never {@code null}. - */ - @Nonnull - DependencyProperties getDependencyProperties(); + boolean isIncludesDependencies(); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java index daa86e7426ec..e06dd9e13cb1 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java +++ b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java @@ -45,7 +45,8 @@ public ArtifactType get(String typeId) { type.getLanguage(), type.getExtension(), type.getClassifier(), - type.getDependencyProperties()); + type.isBuildPathConstituent(), + type.isIncludesDependencies()); } return null; } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java index 7c63b34279c2..5a5b3f9b0515 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java @@ -23,7 +23,6 @@ import org.apache.maven.api.Artifact; import org.apache.maven.api.Dependency; import org.apache.maven.api.DependencyCoordinate; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.DependencyScope; import org.apache.maven.api.Type; import org.apache.maven.api.Version; @@ -37,15 +36,12 @@ public class DefaultDependency implements Dependency { private final InternalSession session; private final org.eclipse.aether.graph.Dependency dependency; - private final DependencyProperties dependencyProperties; private final String key; public DefaultDependency( @Nonnull InternalSession session, @Nonnull org.eclipse.aether.graph.Dependency dependency) { this.session = nonNull(session, "session"); this.dependency = nonNull(dependency, "dependency"); - this.dependencyProperties = - new DefaultDependencyProperties(dependency.getArtifact().getProperties()); this.key = getGroupId() + ':' + getArtifactId() @@ -104,11 +100,6 @@ public Type getType() { return session.requireType(type); } - @Override - public DependencyProperties getDependencyProperties() { - return dependencyProperties; - } - @Override public boolean isSnapshot() { return DefaultModelVersionParser.checkSnapshot(dependency.getArtifact().getVersion()); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java deleted file mode 100644 index 2ee780713034..000000000000 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.internal.impl; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.apache.maven.api.DependencyProperties; -import org.apache.maven.api.annotations.Nonnull; - -import static org.apache.maven.internal.impl.Utils.nonNull; - -/** - * Default implementation of artifact properties. - */ -public class DefaultDependencyProperties implements DependencyProperties { - private final Map properties; - - public DefaultDependencyProperties(String... flags) { - this(Arrays.asList(flags)); - } - - public DefaultDependencyProperties(@Nonnull Collection flags) { - nonNull(flags, "flags"); - HashMap map = new HashMap<>(); - for (String flag : flags) { - map.put(flag, Boolean.TRUE.toString()); - } - this.properties = Collections.unmodifiableMap(map); - } - - public DefaultDependencyProperties(@Nonnull Map properties) { - this.properties = Collections.unmodifiableMap(nonNull(properties, "properties")); - } - - @Nonnull - @Override - public Map asMap() { - return properties; - } - - @Override - public boolean checkFlag(@Nonnull String flag) { - nonNull(flag, "flag"); - return Boolean.parseBoolean(properties.getOrDefault(flag, "")); - } -} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java index b6042784d1d2..9dca04e0ea35 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java @@ -18,10 +18,10 @@ */ package org.apache.maven.internal.impl; +import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; import org.eclipse.aether.artifact.ArtifactProperties; @@ -30,35 +30,34 @@ import static org.apache.maven.internal.impl.Utils.nonNull; public class DefaultType implements Type, ArtifactType { + private final String id; + private final Language language; private final String extension; private final String classifier; - - private final DependencyProperties dependencyProperties; + private final boolean buildPathConstituent; + private final boolean includesDependencies; public DefaultType( String id, Language language, String extension, String classifier, - DependencyProperties dependencyProperties) { - nonNull(id, "id"); - nonNull(language, "language"); - this.language = language; + boolean buildPathConstituent, + boolean includesDependencies) { + this.id = nonNull(id, "id"); + this.language = nonNull(language, "language"); this.extension = nonNull(extension, "extension"); this.classifier = classifier; - nonNull(dependencyProperties, "dependencyProperties"); - HashMap props = new HashMap<>(dependencyProperties.asMap()); - props.put(ArtifactProperties.TYPE, id); - props.put(ArtifactProperties.LANGUAGE, language.id()); - this.dependencyProperties = new DefaultDependencyProperties(props); + this.buildPathConstituent = buildPathConstituent; + this.includesDependencies = includesDependencies; } @Override public String id() { - return dependencyProperties.asMap().get(ArtifactProperties.TYPE); + return id; } @Override @@ -82,12 +81,22 @@ public String getClassifier() { } @Override - public DependencyProperties getDependencyProperties() { - return dependencyProperties; + public boolean isBuildPathConstituent() { + return this.buildPathConstituent; + } + + @Override + public boolean isIncludesDependencies() { + return this.includesDependencies; } @Override public Map getProperties() { - return getDependencyProperties().asMap(); + Map properties = new HashMap<>(); + properties.put(ArtifactProperties.TYPE, this.id); + properties.put(ArtifactProperties.LANGUAGE, this.language.id()); + properties.put(ArtifactProperties.INCLUDES_DEPENDENCIES, String.valueOf(includesDependencies)); + properties.put(ArtifactProperties.CONSTITUTES_BUILD_PATH, String.valueOf(buildPathConstituent)); + return Collections.unmodifiableMap(properties); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java index 76c575c0c413..faf8d4ca9391 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java @@ -22,12 +22,10 @@ import javax.inject.Named; import javax.inject.Singleton; -import java.util.ArrayList; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Type; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.services.LanguageRegistry; @@ -89,19 +87,13 @@ public Type require(String id) { type = legacyTypes.computeIfAbsent(id, k -> { // Copy data as the ArtifactHandler is not immutable, but Type should be. ArtifactHandler handler = manager.getArtifactHandler(id); - ArrayList flags = new ArrayList<>(); - if (handler.isAddedToClasspath()) { - flags.add(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT); - } - if (handler.isIncludesDependencies()) { - flags.add(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES); - } return new DefaultType( id, languageRegistry.require(handler.getLanguage()), handler.getExtension(), handler.getClassifier(), - new DefaultDependencyProperties(flags)); + handler.isAddedToClasspath(), + handler.isIncludesDependencies()); }); } return type; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java index bc7f8042c9da..801bfef782df 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java @@ -24,7 +24,6 @@ import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(BomTypeProvider.NAME) @@ -35,7 +34,7 @@ public class BomTypeProvider implements Provider { private final Type type; public BomTypeProvider() { - this.type = new DefaultType(NAME, Language.NONE, "pom", null, new DefaultDependencyProperties()); + this.type = new DefaultType(NAME, Language.NONE, "pom", null, false, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java index 28dee7cf85c3..5512b8e44224 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EarTypeProvider.NAME) @@ -36,12 +34,7 @@ public class EarTypeProvider implements Provider { private final Type type; public EarTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "ear", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "ear", null, false, true); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java index 03a47874e932..a1a97dfcbb1b 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EjbClientTypeProvider.NAME) @@ -36,12 +34,7 @@ public class EjbClientTypeProvider implements Provider { private final Type type; public EjbClientTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "jar", - "client", - new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "client", true, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java index ed3f50c7928a..01a8dfcb9fec 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(EjbTypeProvider.NAME) @@ -36,12 +34,7 @@ public class EjbTypeProvider implements Provider { private final Type type; public EjbTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "jar", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, true, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java index a4221fbed3d9..df61f6bd3ba5 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(JarTypeProvider.NAME) @@ -36,12 +34,7 @@ public class JarTypeProvider implements Provider { private final Type type; public JarTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "jar", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, true, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java index d16891826505..4e90d4591a58 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java @@ -24,7 +24,6 @@ import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(JavaSourceTypeProvider.NAME) @@ -35,7 +34,7 @@ public class JavaSourceTypeProvider implements Provider { private final Type type; public JavaSourceTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "sources", new DefaultDependencyProperties()); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "sources", false, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java index cfe86c51c653..1f6e9aee8fa0 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(JavadocTypeProvider.NAME) @@ -36,12 +34,7 @@ public class JavadocTypeProvider implements Provider { private final Type type; public JavadocTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "jar", - "javadoc", - new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "javadoc", true, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java index 128e3ee85613..ec5a45ff55ba 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(MavenPluginTypeProvider.NAME) @@ -36,12 +34,7 @@ public class MavenPluginTypeProvider implements Provider { private final Type type; public MavenPluginTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "jar", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, true, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java index d1dda01e349a..b804b6959748 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(ParTypeProvider.NAME) @@ -36,12 +34,7 @@ public class ParTypeProvider implements Provider { private final Type type; public ParTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "par", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "par", null, false, true); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java index b3a078fd2adc..9f385641165a 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java @@ -24,7 +24,6 @@ import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(PomTypeProvider.NAME) @@ -35,7 +34,7 @@ public class PomTypeProvider implements Provider { private final Type type; public PomTypeProvider() { - this.type = new DefaultType(NAME, Language.NONE, "pom", null, new DefaultDependencyProperties()); + this.type = new DefaultType(NAME, Language.NONE, "pom", null, false, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java index 59b0a2882786..39e36777c0ba 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(RarTypeProvider.NAME) @@ -36,12 +34,7 @@ public class RarTypeProvider implements Provider { private final Type type; public RarTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "rar", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "rar", null, false, true); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java index 11ceb7ef2d04..39f9653e9f99 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(TestJarTypeProvider.NAME) @@ -36,12 +34,7 @@ public class TestJarTypeProvider implements Provider { private final Type type; public TestJarTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "jar", - "tests", - new DefaultDependencyProperties(DependencyProperties.FLAG_BUILD_PATH_CONSTITUENT)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "tests", true, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java index d9d36ea277cf..732ff09a7e10 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java @@ -22,10 +22,8 @@ import javax.inject.Provider; import javax.inject.Singleton; -import org.apache.maven.api.DependencyProperties; import org.apache.maven.api.Language; import org.apache.maven.api.Type; -import org.apache.maven.internal.impl.DefaultDependencyProperties; import org.apache.maven.internal.impl.DefaultType; @Named(WarTypeProvider.NAME) @@ -36,12 +34,7 @@ public class WarTypeProvider implements Provider { private final Type type; public WarTypeProvider() { - this.type = new DefaultType( - NAME, - Language.JAVA_FAMILY, - "war", - null, - new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES)); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "war", null, false, true); } @Override From 734910a04a9ddb5e41093a4a41e634ebc585ed02 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 21:23:59 +0100 Subject: [PATCH 23/31] Use a plain enum for DependencyScope which is not extensible --- .../org/apache/maven/api/DependencyScope.java | 62 ++++++++++++++----- .../org/apache/maven/api/ExtensibleEnums.java | 18 ------ .../api/services/DependencyScopeRegistry.java | 23 ------- .../api/spi/DependencyScopeProvider.java | 23 ------- .../maven/internal/impl/AbstractSession.java | 2 +- .../impl/ExtensibleEnumRegistries.java | 23 ------- 6 files changed, 48 insertions(+), 103 deletions(-) delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyScopeRegistry.java delete mode 100644 api/maven-api-spi/src/main/java/org/apache/maven/api/spi/DependencyScopeProvider.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java index f3d26aa0686f..2951acb1b44c 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java @@ -18,10 +18,14 @@ */ package org.apache.maven.api; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; - -import static org.apache.maven.api.ExtensibleEnums.dependencyScope; +import org.apache.maven.api.annotations.Nonnull; /** * Dependency scope. @@ -33,55 +37,53 @@ */ @Experimental @Immutable -public interface DependencyScope extends ExtensibleEnum { - - boolean isTransitive(); +public enum DependencyScope { /** * None. Allows you to declare dependencies (for example to alter reactor build order) but in reality dependencies * in this scope are not part of any build path scope. */ - DependencyScope NONE = dependencyScope("none", false); + NONE("none", false), /** * Empty scope. */ - DependencyScope EMPTY = dependencyScope("", false); + EMPTY("", false), /** * Compile only. */ - DependencyScope COMPILE_ONLY = dependencyScope("compile-only", false); + COMPILE_ONLY("compile-only", false), /** * Compile. */ - DependencyScope COMPILE = dependencyScope("compile", true); + COMPILE("compile", true), /** * Runtime. */ - DependencyScope RUNTIME = dependencyScope("runtime", true); + RUNTIME("runtime", true), /** * Provided. */ - DependencyScope PROVIDED = dependencyScope("provided", false); + PROVIDED("provided", false), /** * Test compile only. */ - DependencyScope TEST_ONLY = dependencyScope("test-only", false); + TEST_ONLY("test-only", false), /** * Test. */ - DependencyScope TEST = dependencyScope("test", false); + TEST("test", false), /** * Test runtime. */ - DependencyScope TEST_RUNTIME = dependencyScope("test-runtime", true); + TEST_RUNTIME("test-runtime", true), /** * System scope. @@ -89,5 +91,35 @@ public interface DependencyScope extends ExtensibleEnum { * Important: this scope {@code id} MUST BE KEPT in sync with label in * {@code org.eclipse.aether.util.artifact.Scopes#SYSTEM}. */ - DependencyScope SYSTEM = dependencyScope("system", false); + SYSTEM("system", false); + + private static final Map IDS = Collections.unmodifiableMap( + Stream.of(DependencyScope.values()).collect(Collectors.toMap(s -> s.id, s -> s))); + + public static DependencyScope forId(String id) { + return IDS.get(id); + } + + private final String id; + private final boolean transitive; + + DependencyScope(String id, boolean transitive) { + this.id = id; + this.transitive = transitive; + } + + /** + * The {@code id} uniquely represents a value for this extensible enum. + * This id should be used to compute the equality and hash code for the instance. + * + * @return the id + */ + @Nonnull + public String id() { + return id; + } + + public boolean isTransitive() { + return transitive; + } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java index 4035842b6caf..6c2504f501d4 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java @@ -26,10 +26,6 @@ static Language language(String id) { return new DefaultLanguage(id); } - static DependencyScope dependencyScope(String id, boolean transitive) { - return new DefaultDependencyScope(id, transitive); - } - static BuildPathScope buildPathScope(String id, ProjectScope projectScope, DependencyScope... dependencyScopes) { return new DefaultBuildPathScope(id, projectScope, dependencyScopes); } @@ -66,20 +62,6 @@ public String toString() { } } - private static class DefaultDependencyScope extends DefaultExtensibleEnum implements DependencyScope { - private final boolean transitive; - - DefaultDependencyScope(String id, boolean transitive) { - super(id); - this.transitive = transitive; - } - - @Override - public boolean isTransitive() { - return transitive; - } - } - private static class DefaultBuildPathScope extends DefaultExtensibleEnum implements BuildPathScope { private final ProjectScope projectScope; private final Set dependencyScopes; diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyScopeRegistry.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyScopeRegistry.java deleted file mode 100644 index 1b3df452a928..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyScopeRegistry.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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.services; - -import org.apache.maven.api.DependencyScope; - -public interface DependencyScopeRegistry extends ExtensibleEnumRegistry {} diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/DependencyScopeProvider.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/DependencyScopeProvider.java deleted file mode 100644 index a7ed7e6568ba..000000000000 --- a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/DependencyScopeProvider.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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.spi; - -import org.apache.maven.api.DependencyScope; - -public interface DependencyScopeProvider extends ExtensibleEnumProvider {} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index 18e91be78414..4719f0be201c 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -541,7 +541,7 @@ public ProjectScope requireProjectScope(String id) { @Override public DependencyScope requireDependencyScope(String id) { - return getService(DependencyScopeRegistry.class).require(id); + return DependencyScope.forId(id); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java index e6011bf6679e..bc7754b36aad 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java @@ -52,29 +52,6 @@ public DefaultBuildPathScopeRegistry(List providers) { } } - @Named - @SessionScoped - public static class DefaultDependencyScopeRegistry - extends DefaultExtensibleEnumRegistry - implements DependencyScopeRegistry { - - @Inject - public DefaultDependencyScopeRegistry(List providers) { - super( - providers, - DependencyScope.NONE, - DependencyScope.EMPTY, - DependencyScope.COMPILE_ONLY, - DependencyScope.COMPILE, - DependencyScope.RUNTIME, - DependencyScope.PROVIDED, - DependencyScope.TEST_ONLY, - DependencyScope.TEST, - DependencyScope.TEST_RUNTIME, - DependencyScope.SYSTEM); - } - } - @Named @SessionScoped public static class DefaultProjectScopeRegistry From 3d2df726aef2c364f0c5803b46b7a31dd1527282 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 22:23:21 +0100 Subject: [PATCH 24/31] Remove unused BuildPath --- .../java/org/apache/maven/api/BuildPath.java | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java b/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java deleted file mode 100644 index 970e73e063b4..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPath.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.util.Collection; - -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.annotations.Immutable; -import org.apache.maven.api.annotations.Nonnull; - -/** - * Build path. Build path is calculated for given {@link Project} and {@link BuildPathScope}. - * - * @since 4.0.0 - */ -@Experimental -@Immutable -public interface BuildPath { - @Nonnull - Project project(); - - @Nonnull - BuildPathScope buildPathScope(); - - @Nonnull - default Language language() { - return project().getLanguage(); - } - - @Nonnull - Collection getArtifacts(); -} From 3b2bc64caf9b0af4740edbca5ebb0f9d4591f093 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 22:28:33 +0100 Subject: [PATCH 25/31] Rename BuildPathScope -> PathScope --- .../org/apache/maven/api/ExtensibleEnums.java | 8 +++--- .../{BuildPathScope.java => PathScope.java} | 12 ++++----- .../java/org/apache/maven/api/Session.java | 8 +++--- .../api/services/DependencyResolver.java | 12 ++++----- .../services/DependencyResolverRequest.java | 26 +++++++++---------- ...peRegistry.java => PathScopeRegistry.java} | 4 +-- ...peProvider.java => PathScopeProvider.java} | 4 +-- .../maven/internal/impl/AbstractSession.java | 8 +++--- .../impl/DefaultDependencyResolver.java | 8 +++--- .../impl/ExtensibleEnumRegistries.java | 16 ++++++------ .../apache/maven/internal/impl/TestApi.java | 2 +- 11 files changed, 54 insertions(+), 54 deletions(-) rename api/maven-api-core/src/main/java/org/apache/maven/api/{BuildPathScope.java => PathScope.java} (87%) rename api/maven-api-core/src/main/java/org/apache/maven/api/services/{BuildPathScopeRegistry.java => PathScopeRegistry.java} (86%) rename api/maven-api-spi/src/main/java/org/apache/maven/api/spi/{BuildPathScopeProvider.java => PathScopeProvider.java} (86%) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java index 6c2504f501d4..7843cbef7066 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnums.java @@ -26,8 +26,8 @@ static Language language(String id) { return new DefaultLanguage(id); } - static BuildPathScope buildPathScope(String id, ProjectScope projectScope, DependencyScope... dependencyScopes) { - return new DefaultBuildPathScope(id, projectScope, dependencyScopes); + static PathScope pathScope(String id, ProjectScope projectScope, DependencyScope... dependencyScopes) { + return new DefaultPathScope(id, projectScope, dependencyScopes); } static ProjectScope projectScope(String id) { @@ -62,11 +62,11 @@ public String toString() { } } - private static class DefaultBuildPathScope extends DefaultExtensibleEnum implements BuildPathScope { + private static class DefaultPathScope extends DefaultExtensibleEnum implements PathScope { private final ProjectScope projectScope; private final Set dependencyScopes; - DefaultBuildPathScope(String id, ProjectScope projectScope, DependencyScope... dependencyScopes) { + DefaultPathScope(String id, ProjectScope projectScope, DependencyScope... dependencyScopes) { super(id); this.projectScope = Objects.requireNonNull(projectScope); this.dependencyScopes = diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/PathScope.java similarity index 87% rename from api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java rename to api/maven-api-core/src/main/java/org/apache/maven/api/PathScope.java index 5cff60cf87d9..7132dfaa7e54 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/BuildPathScope.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/PathScope.java @@ -24,7 +24,7 @@ import org.apache.maven.api.annotations.Immutable; import org.apache.maven.api.annotations.Nonnull; -import static org.apache.maven.api.ExtensibleEnums.buildPathScope; +import static org.apache.maven.api.ExtensibleEnums.pathScope; /** * Build path scope. @@ -36,7 +36,7 @@ */ @Experimental @Immutable -public interface BuildPathScope extends ExtensibleEnum { +public interface PathScope extends ExtensibleEnum { @Nonnull ProjectScope projectScope(); @@ -44,7 +44,7 @@ public interface BuildPathScope extends ExtensibleEnum { @Nonnull Set dependencyScopes(); - BuildPathScope MAIN_COMPILE = buildPathScope( + PathScope MAIN_COMPILE = pathScope( "main-compile", ProjectScope.MAIN, DependencyScope.EMPTY, @@ -52,10 +52,10 @@ public interface BuildPathScope extends ExtensibleEnum { DependencyScope.COMPILE, DependencyScope.PROVIDED); - BuildPathScope MAIN_RUNTIME = buildPathScope( + PathScope MAIN_RUNTIME = pathScope( "main-runtime", ProjectScope.MAIN, DependencyScope.EMPTY, DependencyScope.COMPILE, DependencyScope.RUNTIME); - BuildPathScope TEST_COMPILE = buildPathScope( + PathScope TEST_COMPILE = pathScope( "test-compile", ProjectScope.TEST, DependencyScope.EMPTY, @@ -64,7 +64,7 @@ public interface BuildPathScope extends ExtensibleEnum { DependencyScope.TEST_ONLY, DependencyScope.TEST); - BuildPathScope TEST_RUNTIME = buildPathScope( + PathScope TEST_RUNTIME = pathScope( "test-runtime", ProjectScope.TEST, DependencyScope.EMPTY, diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index bc6105f99b65..329e57ed72aa 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -427,11 +427,11 @@ Artifact createArtifact( /** * Shortcut for {@code getService(DependencyResolver.class).flatten(...)}. * - * @see org.apache.maven.api.services.DependencyResolver#flatten(Session, Node, BuildPathScope) + * @see org.apache.maven.api.services.DependencyResolver#flatten(Session, Node, PathScope) * @throws org.apache.maven.api.services.DependencyResolverException if the dependency flattening failed */ @Nonnull - List flattenDependencies(@Nonnull Node node, @Nonnull BuildPathScope scope); + List flattenDependencies(@Nonnull Node node, @Nonnull PathScope scope); @Nonnull List resolveDependencies(@Nonnull DependencyCoordinate dependencyCoordinate); @@ -440,7 +440,7 @@ Artifact createArtifact( List resolveDependencies(@Nonnull List dependencyCoordinates); @Nonnull - List resolveDependencies(@Nonnull Project project, @Nonnull BuildPathScope scope); + List resolveDependencies(@Nonnull Project project, @Nonnull PathScope scope); /** * Resolves an artifact's meta version (if any) to a concrete version. For example, resolves "1.0-SNAPSHOT" @@ -512,5 +512,5 @@ Artifact createArtifact( DependencyScope requireDependencyScope(String id); - BuildPathScope requireBuildPathScope(String id); + PathScope requireBuildPathScope(String id); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java index 440b1b3f023a..4a8e90ea6503 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java @@ -20,7 +20,7 @@ import java.util.List; -import org.apache.maven.api.BuildPathScope; +import org.apache.maven.api.PathScope; import org.apache.maven.api.DependencyCoordinate; import org.apache.maven.api.Node; import org.apache.maven.api.Project; @@ -35,7 +35,7 @@ @Experimental public interface DependencyResolver extends Service { - List flatten(Session session, Node node, BuildPathScope scope) throws DependencyResolverException; + List flatten(Session session, Node node, PathScope scope) throws DependencyResolverException; /** * This method collects, flattens and resolves the dependencies. @@ -47,7 +47,7 @@ public interface DependencyResolver extends Service { * @throws ArtifactResolverException * * @see DependencyCollector#collect(DependencyCollectorRequest) - * @see #flatten(Session, Node, BuildPathScope) + * @see #flatten(Session, Node, PathScope) * @see ArtifactResolver#resolve(ArtifactResolverRequest) */ DependencyResolverResult resolve(DependencyResolverRequest request) @@ -60,7 +60,7 @@ default DependencyResolverResult resolve(@Nonnull Session session, @Nonnull Proj @Nonnull default DependencyResolverResult resolve( - @Nonnull Session session, @Nonnull Project project, @Nonnull BuildPathScope scope) { + @Nonnull Session session, @Nonnull Project project, @Nonnull PathScope scope) { return resolve(DependencyResolverRequest.build(session, project, scope)); } @@ -71,7 +71,7 @@ default DependencyResolverResult resolve(@Nonnull Session session, @Nonnull Depe @Nonnull default DependencyResolverResult resolve( - @Nonnull Session session, @Nonnull DependencyCoordinate dependency, @Nonnull BuildPathScope scope) { + @Nonnull Session session, @Nonnull DependencyCoordinate dependency, @Nonnull PathScope scope) { return resolve(DependencyResolverRequest.build(session, dependency, scope)); } @@ -83,7 +83,7 @@ default DependencyResolverResult resolve( @Nonnull default DependencyResolverResult resolve( - @Nonnull Session session, @Nonnull List dependencies, @Nonnull BuildPathScope scope) { + @Nonnull Session session, @Nonnull List dependencies, @Nonnull PathScope scope) { return resolve(DependencyResolverRequest.build(session, dependencies, scope)); } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java index 454766ec83c3..3f6a381f6fb0 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java @@ -22,7 +22,7 @@ import java.util.List; import org.apache.maven.api.Artifact; -import org.apache.maven.api.BuildPathScope; +import org.apache.maven.api.PathScope; import org.apache.maven.api.DependencyCoordinate; import org.apache.maven.api.Project; import org.apache.maven.api.Session; @@ -35,7 +35,7 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest { @Nonnull - BuildPathScope getResolutionScope(); + PathScope getResolutionScope(); @Nonnull static DependencyResolverRequestBuilder builder() { @@ -44,11 +44,11 @@ static DependencyResolverRequestBuilder builder() { @Nonnull static DependencyResolverRequest build(Session session, Project project) { - return build(session, project, BuildPathScope.MAIN_RUNTIME); + return build(session, project, PathScope.MAIN_RUNTIME); } @Nonnull - static DependencyResolverRequest build(Session session, Project project, BuildPathScope scope) { + static DependencyResolverRequest build(Session session, Project project, PathScope scope) { return new DependencyResolverRequestBuilder() .session(session) .project(project) @@ -58,11 +58,11 @@ static DependencyResolverRequest build(Session session, Project project, BuildPa @Nonnull static DependencyResolverRequest build(Session session, DependencyCoordinate dependency) { - return build(session, dependency, BuildPathScope.MAIN_RUNTIME); + return build(session, dependency, PathScope.MAIN_RUNTIME); } @Nonnull - static DependencyResolverRequest build(Session session, DependencyCoordinate dependency, BuildPathScope scope) { + static DependencyResolverRequest build(Session session, DependencyCoordinate dependency, PathScope scope) { return new DependencyResolverRequestBuilder() .session(session) .dependency(dependency) @@ -72,12 +72,12 @@ static DependencyResolverRequest build(Session session, DependencyCoordinate dep @Nonnull static DependencyResolverRequest build(Session session, List dependencies) { - return build(session, dependencies, BuildPathScope.MAIN_RUNTIME); + return build(session, dependencies, PathScope.MAIN_RUNTIME); } @Nonnull static DependencyResolverRequest build( - Session session, List dependencies, BuildPathScope scope) { + Session session, List dependencies, PathScope scope) { return new DependencyResolverRequestBuilder() .session(session) .dependencies(dependencies) @@ -87,7 +87,7 @@ static DependencyResolverRequest build( @NotThreadSafe class DependencyResolverRequestBuilder extends DependencyCollectorRequestBuilder { - BuildPathScope resolutionScope; + PathScope resolutionScope; @Nonnull @Override @@ -154,7 +154,7 @@ public DependencyResolverRequestBuilder verbose(boolean verbose) { } @Nonnull - public DependencyResolverRequestBuilder resolutionScope(@Nonnull BuildPathScope resolutionScope) { + public DependencyResolverRequestBuilder resolutionScope(@Nonnull PathScope resolutionScope) { this.resolutionScope = resolutionScope; return this; } @@ -167,7 +167,7 @@ public DependencyResolverRequest build() { static class DefaultDependencyResolverRequest extends DefaultDependencyCollectorRequest implements DependencyResolverRequest { - private final BuildPathScope resolutionScope; + private final PathScope resolutionScope; DefaultDependencyResolverRequest( Session session, @@ -177,7 +177,7 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector Collection dependencies, Collection managedDependencies, boolean verbose, - BuildPathScope resolutionScope) { + PathScope resolutionScope) { super(session, project, rootArtifact, root, dependencies, managedDependencies, verbose); this.resolutionScope = nonNull(resolutionScope, "resolutionScope cannot be null"); if (verbose) { @@ -187,7 +187,7 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector @Nonnull @Override - public BuildPathScope getResolutionScope() { + public PathScope getResolutionScope() { return resolutionScope; } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuildPathScopeRegistry.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathScopeRegistry.java similarity index 86% rename from api/maven-api-core/src/main/java/org/apache/maven/api/services/BuildPathScopeRegistry.java rename to api/maven-api-core/src/main/java/org/apache/maven/api/services/PathScopeRegistry.java index c3ff0c223ff2..06b5d5964733 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuildPathScopeRegistry.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathScopeRegistry.java @@ -18,6 +18,6 @@ */ package org.apache.maven.api.services; -import org.apache.maven.api.BuildPathScope; +import org.apache.maven.api.PathScope; -public interface BuildPathScopeRegistry extends ExtensibleEnumRegistry {} +public interface PathScopeRegistry extends ExtensibleEnumRegistry {} diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/BuildPathScopeProvider.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/PathScopeProvider.java similarity index 86% rename from api/maven-api-spi/src/main/java/org/apache/maven/api/spi/BuildPathScopeProvider.java rename to api/maven-api-spi/src/main/java/org/apache/maven/api/spi/PathScopeProvider.java index 3e8a54652178..2e2597b839d0 100644 --- a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/BuildPathScopeProvider.java +++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/PathScopeProvider.java @@ -18,6 +18,6 @@ */ package org.apache.maven.api.spi; -import org.apache.maven.api.BuildPathScope; +import org.apache.maven.api.PathScope; -public interface BuildPathScopeProvider extends ExtensibleEnumProvider {} +public interface PathScopeProvider extends ExtensibleEnumProvider {} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index 4719f0be201c..9e77d11c6a0f 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -462,7 +462,7 @@ public Node collectDependencies(@Nonnull DependencyCoordinate dependency) { @Nonnull @Override - public List flattenDependencies(@Nonnull Node node, @Nonnull BuildPathScope scope) { + public List flattenDependencies(@Nonnull Node node, @Nonnull PathScope scope) { return getService(DependencyResolver.class).flatten(this, node, scope); } @@ -477,7 +477,7 @@ public List resolveDependencies(List dependencies) { } @Override - public List resolveDependencies(Project project, BuildPathScope scope) { + public List resolveDependencies(Project project, PathScope scope) { return getService(DependencyResolver.class) .resolve(this, project, scope) .getPaths(); @@ -545,7 +545,7 @@ public DependencyScope requireDependencyScope(String id) { } @Override - public BuildPathScope requireBuildPathScope(String id) { - return getService(BuildPathScopeRegistry.class).require(id); + public PathScope requireBuildPathScope(String id) { + return getService(PathScopeRegistry.class).require(id); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java index 14bb73953403..d2b8eb549f88 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java @@ -51,7 +51,7 @@ public class DefaultDependencyResolver implements DependencyResolver { @Override - public List flatten(Session s, Node node, BuildPathScope scope) throws DependencyResolverException { + public List flatten(Session s, Node node, PathScope scope) throws DependencyResolverException { InternalSession session = InternalSession.from(s); DependencyNode root = cast(AbstractNode.class, node, "node").getDependencyNode(); List dependencies = session.getRepositorySystem() @@ -60,7 +60,7 @@ public List flatten(Session s, Node node, BuildPathScope scope) throws Dep return map(dependencies, session::getNode); } - private static DependencyFilter getScopeDependencyFilter(BuildPathScope scope) { + private static DependencyFilter getScopeDependencyFilter(PathScope scope) { Set scopes = scope.dependencyScopes().stream().map(DependencyScope::id).collect(Collectors.toSet()); return (n, p) -> { @@ -124,7 +124,7 @@ private Stream stream(DependencyNode node) { return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(this::stream)); } - private DependencyResolutionResult resolveDependencies(Session session, Project project, BuildPathScope scope) { + private DependencyResolutionResult resolveDependencies(Session session, Project project, PathScope scope) { Collection toResolve = toScopes(scope); try { LifecycleDependencyResolver lifecycleDependencyResolver = @@ -145,7 +145,7 @@ private MavenProject getMavenProject(Project project) { return ((DefaultProject) project).getProject(); } - private Collection toScopes(BuildPathScope scope) { + private Collection toScopes(PathScope scope) { return map(scope.dependencyScopes(), DependencyScope::id); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java index bc7754b36aad..2eff69ce8cc1 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java @@ -37,18 +37,18 @@ public class ExtensibleEnumRegistries { @Named @SessionScoped - public static class DefaultBuildPathScopeRegistry - extends DefaultExtensibleEnumRegistry - implements BuildPathScopeRegistry { + public static class DefaultPathScopeRegistry + extends DefaultExtensibleEnumRegistry + implements PathScopeRegistry { @Inject - public DefaultBuildPathScopeRegistry(List providers) { + public DefaultPathScopeRegistry(List providers) { super( providers, - BuildPathScope.MAIN_COMPILE, - BuildPathScope.MAIN_RUNTIME, - BuildPathScope.TEST_COMPILE, - BuildPathScope.TEST_RUNTIME); + PathScope.MAIN_COMPILE, + PathScope.MAIN_RUNTIME, + PathScope.TEST_COMPILE, + PathScope.TEST_RUNTIME); } } diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java index 9f165930708e..18ce020307f5 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java +++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java @@ -194,7 +194,7 @@ void testProjectDependencies() { assertNotNull(root); DependencyResolverResult result = - session.getService(DependencyResolver.class).resolve(session, project, BuildPathScope.MAIN_RUNTIME); + session.getService(DependencyResolver.class).resolve(session, project, PathScope.MAIN_RUNTIME); assertNotNull(result); List deps = new ArrayList<>(result.getDependencies().keySet()); List deps2 = result.getNodes().stream() From e40f20f576f93cb35f04233cbd5ad2fddb0b847f Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 31 Jan 2024 22:28:33 +0100 Subject: [PATCH 26/31] Rename BuildPathScope -> PathScope --- .../java/org/apache/maven/api/Session.java | 2 +- .../api/services/DependencyResolver.java | 2 +- .../services/DependencyResolverRequest.java | 31 +++++++++---------- .../maven/internal/impl/AbstractSession.java | 2 +- .../impl/DefaultDependencyResolver.java | 4 +-- .../impl/ExtensibleEnumRegistries.java | 3 +- 6 files changed, 21 insertions(+), 23 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index 329e57ed72aa..4f414fe1fe0c 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -512,5 +512,5 @@ Artifact createArtifact( DependencyScope requireDependencyScope(String id); - PathScope requireBuildPathScope(String id); + PathScope requirePathScope(String id); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java index 4a8e90ea6503..9fefbc4cda7c 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java @@ -20,9 +20,9 @@ import java.util.List; -import org.apache.maven.api.PathScope; import org.apache.maven.api.DependencyCoordinate; import org.apache.maven.api.Node; +import org.apache.maven.api.PathScope; import org.apache.maven.api.Project; import org.apache.maven.api.Service; import org.apache.maven.api.Session; diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java index 3f6a381f6fb0..6d8f00935379 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java @@ -22,8 +22,8 @@ import java.util.List; import org.apache.maven.api.Artifact; -import org.apache.maven.api.PathScope; import org.apache.maven.api.DependencyCoordinate; +import org.apache.maven.api.PathScope; import org.apache.maven.api.Project; import org.apache.maven.api.Session; import org.apache.maven.api.annotations.Experimental; @@ -35,7 +35,7 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest { @Nonnull - PathScope getResolutionScope(); + PathScope getPathScope(); @Nonnull static DependencyResolverRequestBuilder builder() { @@ -52,7 +52,7 @@ static DependencyResolverRequest build(Session session, Project project, PathSco return new DependencyResolverRequestBuilder() .session(session) .project(project) - .resolutionScope(scope) + .pathScope(scope) .build(); } @@ -66,7 +66,7 @@ static DependencyResolverRequest build(Session session, DependencyCoordinate dep return new DependencyResolverRequestBuilder() .session(session) .dependency(dependency) - .resolutionScope(scope) + .pathScope(scope) .build(); } @@ -76,18 +76,17 @@ static DependencyResolverRequest build(Session session, List dependencies, PathScope scope) { + static DependencyResolverRequest build(Session session, List dependencies, PathScope scope) { return new DependencyResolverRequestBuilder() .session(session) .dependencies(dependencies) - .resolutionScope(scope) + .pathScope(scope) .build(); } @NotThreadSafe class DependencyResolverRequestBuilder extends DependencyCollectorRequestBuilder { - PathScope resolutionScope; + PathScope pathScope; @Nonnull @Override @@ -154,20 +153,20 @@ public DependencyResolverRequestBuilder verbose(boolean verbose) { } @Nonnull - public DependencyResolverRequestBuilder resolutionScope(@Nonnull PathScope resolutionScope) { - this.resolutionScope = resolutionScope; + public DependencyResolverRequestBuilder pathScope(@Nonnull PathScope pathScope) { + this.pathScope = pathScope; return this; } @Override public DependencyResolverRequest build() { return new DefaultDependencyResolverRequest( - session, project, rootArtifact, root, dependencies, managedDependencies, verbose, resolutionScope); + session, project, rootArtifact, root, dependencies, managedDependencies, verbose, pathScope); } static class DefaultDependencyResolverRequest extends DefaultDependencyCollectorRequest implements DependencyResolverRequest { - private final PathScope resolutionScope; + private final PathScope pathScope; DefaultDependencyResolverRequest( Session session, @@ -177,9 +176,9 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector Collection dependencies, Collection managedDependencies, boolean verbose, - PathScope resolutionScope) { + PathScope pathScope) { super(session, project, rootArtifact, root, dependencies, managedDependencies, verbose); - this.resolutionScope = nonNull(resolutionScope, "resolutionScope cannot be null"); + this.pathScope = nonNull(pathScope, "pathScope cannot be null"); if (verbose) { throw new IllegalArgumentException("verbose cannot be true for resolving dependencies"); } @@ -187,8 +186,8 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector @Nonnull @Override - public PathScope getResolutionScope() { - return resolutionScope; + public PathScope getPathScope() { + return pathScope; } } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index 9e77d11c6a0f..1b9779011986 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -545,7 +545,7 @@ public DependencyScope requireDependencyScope(String id) { } @Override - public PathScope requireBuildPathScope(String id) { + public PathScope requirePathScope(String id) { return getService(PathScopeRegistry.class).require(id); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java index d2b8eb549f88..298576d5f4b6 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java @@ -77,7 +77,7 @@ public DependencyResolverResult resolve(DependencyResolverRequest request) if (request.getProject().isPresent()) { DependencyResolutionResult result = resolveDependencies( - request.getSession(), request.getProject().get(), request.getResolutionScope()); + request.getSession(), request.getProject().get(), request.getPathScope()); Map nodes = stream( result.getDependencyGraph()) @@ -100,7 +100,7 @@ public DependencyResolverResult resolve(DependencyResolverRequest request) DependencyCollectorResult collectorResult = session.getService(DependencyCollector.class).collect(request); - List nodes = flatten(session, collectorResult.getRoot(), request.getResolutionScope()); + List nodes = flatten(session, collectorResult.getRoot(), request.getPathScope()); List deps = nodes.stream().map(Node::getDependency).filter(Objects::nonNull).collect(Collectors.toList()); List coordinates = diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java index 2eff69ce8cc1..d512e74b4635 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/ExtensibleEnumRegistries.java @@ -37,8 +37,7 @@ public class ExtensibleEnumRegistries { @Named @SessionScoped - public static class DefaultPathScopeRegistry - extends DefaultExtensibleEnumRegistry + public static class DefaultPathScopeRegistry extends DefaultExtensibleEnumRegistry implements PathScopeRegistry { @Inject From c535260586d7eb34c56e836b8385f97ee6c3b9a0 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sun, 7 Jan 2024 14:57:09 +0100 Subject: [PATCH 27/31] [MNG-8015] Control the type of path where each dependency can be placed - Refactor some `MavenProject` methods for reducing code duplication. Their behavior should be as before. - Add `@Override` annotations. --- .../java/org/apache/maven/api/Dependency.java | 1 + .../org/apache/maven/api/ExtensibleEnum.java | 2 + .../org/apache/maven/api/JavaPathType.java | 319 ++++++++++++++++ .../java/org/apache/maven/api/PathType.java | 102 +++++ .../main/java/org/apache/maven/api/Type.java | 75 +++- .../services/DependencyResolverRequest.java | 42 ++- .../services/DependencyResolverResult.java | 46 +++ .../maven/artifact/DefaultArtifact.java | 47 +++ .../artifact/handler/ArtifactHandler.java | 11 +- .../artifact/handler/ArtifactHandlerMock.java | 9 + .../maven/repository/TestArtifactHandler.java | 8 + .../handler/DefaultArtifactHandler.java | 3 + .../DefaultArtifactHandlerManager.java | 6 +- .../internal/aether/TypeRegistryAdapter.java | 5 +- .../internal/impl/DefaultDependency.java | 1 + .../impl/DefaultDependencyResolver.java | 141 +++---- .../impl/DefaultDependencyResolverResult.java | 352 ++++++++++++++++++ .../maven/internal/impl/DefaultType.java | 25 +- .../internal/impl/DefaultTypeRegistry.java | 5 +- .../internal/impl/PathModularization.java | 265 +++++++++++++ .../impl/PathModularizationCache.java | 135 +++++++ .../internal/impl/types/BomTypeProvider.java | 2 +- .../impl/types/ClasspathJarTypeProvider.java | 51 +++ .../internal/impl/types/EarTypeProvider.java | 2 +- .../impl/types/EjbClientTypeProvider.java | 3 +- .../internal/impl/types/EjbTypeProvider.java | 3 +- .../internal/impl/types/JarTypeProvider.java | 14 +- .../impl/types/JavaSourceTypeProvider.java | 9 +- .../impl/types/JavadocTypeProvider.java | 10 +- .../impl/types/MavenPluginTypeProvider.java | 10 +- .../impl/types/ModularJarTypeProvider.java | 51 +++ .../internal/impl/types/ParTypeProvider.java | 2 +- .../internal/impl/types/PomTypeProvider.java | 9 +- .../internal/impl/types/RarTypeProvider.java | 2 +- .../impl/types/TestJarTypeProvider.java | 13 +- .../internal/impl/types/WarTypeProvider.java | 2 +- .../impl/TransformedArtifactHandler.java | 8 + .../apache/maven/project/MavenProject.java | 149 ++++---- .../project/artifact/PluginArtifact.java | 8 + .../project/artifact/ProjectArtifact.java | 8 + .../apache/maven/internal/impl/TestApi.java | 2 +- .../internal/impl/TestArtifactHandler.java | 8 + .../internal/FatArtifactTraverser.java | 54 +++ .../internal/MavenRepositorySystemUtils.java | 1 - 44 files changed, 1824 insertions(+), 197 deletions(-) create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/types/ClasspathJarTypeProvider.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/types/ModularJarTypeProvider.java create mode 100644 maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/FatArtifactTraverser.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java index b64fffc0d5e0..d0906581b62f 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java @@ -41,5 +41,6 @@ public interface Dependency extends Artifact { * @return a {@link DependencyCoordinate} */ @Nonnull + @Override DependencyCoordinate toCoordinate(); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnum.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnum.java index 87d80075dd5a..5e29a498c847 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnum.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ExtensibleEnum.java @@ -21,6 +21,8 @@ import org.apache.maven.api.annotations.Nonnull; /** + * Interface that defines some kind of enums that can be extended by Maven plugins or extensions. + * * Implementation must have {@code equals()} and {@code hashCode()} implemented, so implementations of this interface * can be used as keys. */ diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java new file mode 100644 index 000000000000..a34b686c8c2c --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java @@ -0,0 +1,319 @@ +/* + * 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. + * + *

          One path type is handled in a special way: unlike 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.

          + * + *

          Path types are often exclusive. For example, a dependency should not be both on the Java class-path + * and on the Java module-path.

          + * + * @see org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths() + * + * @since 4.0.0 + */ +@Experimental +public enum JavaPathType implements PathType { + /** + * The path identified by the Java {@code --class-path} option. + * Used for compilation, execution and Javadoc among others. + * + *

          Context-sensitive interpretation: + * A dependency with this path type will not necessarily be placed on the class-path. + * There are two circumstances where the dependency may nevertheless be placed somewhere else: + *

          + *
            + *
          • 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).
          • + *
          • If a {@link #patchModule(String)} is also set and the main JAR file is placed on the module-path, + * then the test dependency will be placed on the Java {@code --patch-module} option instead of the + * class-path.
          • + *
          + */ + CLASSES("--class-path"), + + /** + * The path identified by the Java {@code --module-path} option. + * Used for compilation, execution and Javadoc among others. + * + *

          Context-sensitive interpretation: + * A dependency with this flag will not necessarily be placed on the module-path. + * There are two circumstances where the dependency may nevertheless be placed somewhere else: + *

          + *
            + *
          • If {@link #CLASSES} path type is also set, then the dependency should be placed on the + * module-path, but is also 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.
          • + *
          • If a {@link #patchModule(String)} is also set and the main JAR file is placed on the module-path, + * then the test dependency will be placed on the Java {@code --patch-module} option instead of the + * {@code --module-path} option.
          • + *
          + */ + MODULES("--module-path"), + + /** + * The path identified by the Java {@code --upgrade-module-path} option. + */ + UPGRADE_MODULES("--upgrade-module-path"), + + /** + * The path identified by the Java {@code --patch-module} option. + * Note that this option is incomplete, because it must be followed by a module name. + * Use this type only when the module to patch is unknown. + * + * @see #patchModule(String) + */ + PATCH_MODULE("--patch-module"), + + /** + * The path identified by the Java {@code --processor-path} option. + */ + PROCESSOR_CLASSES("--processor-path"), + + /** + * The path identified by the Java {@code --processor-module-path} option. + */ + PROCESSOR_MODULES("--processor-module-path"), + + /** + * The path identified by the Java {@code -agentpath} option. + */ + AGENT("-agentpath"), + + /** + * The path identified by the Javadoc {@code -doclet} option. + */ + DOCLET("-doclet"), + + /** + * The path identified by the Javadoc {@code -tagletpath} option. + */ + TAGLETS("-tagletpath"); + + /** + * Creates a path identified by the Java {@code --patch-module} option. + * Contrarily to the other types of paths, this path is applied to only + * one specific module. Used for compilation and execution among others. + * + *

          Context-sensitive interpretation: + * This path type makes sense only when a main module is added on the module-path by another dependency. + * In no main module is found, the patch dependency may be added on the class-path or module-path + * depending on whether {@link #CLASSES} or {@link #MODULES} is present. + *

          + * + * @param moduleName name of the module on which to apply the path + * @return an identification of the patch-module path for the given module. + * + * @see Modular#moduleName() + */ + @Nonnull + public static Modular patchModule(@Nonnull String moduleName) { + return PATCH_MODULE.new Modular(moduleName); + } + + /** + * The tools option for this path, or {@code null} if none. + * + * @see #option() + */ + private final String option; + + /** + * Creates a new enumeration value for a path associated to the given tool option. + * + * @param option the Java tools option for this path, or {@code null} if none + */ + JavaPathType(String option) { + this.option = option; + } + + @Override + public String id() { + return name(); + } + + /** + * Returns the name of the tool option for this path. For example, if this path type + * is {@link #MODULES}, then this method returns {@code "--module-path"}. The option + * does not include the {@linkplain Modular#moduleName() module name} on which it applies. + * + * @return the name of the tool option for this path type + */ + @Nonnull + @Override + public Optional option() { + return Optional.ofNullable(option); + } + + /** + * Returns the option followed by a string representation of the given path elements. + * For example, if this type is {@link #MODULES}, then the option is {@code "--module-path"} + * followed by the specified path elements. + * + * @param paths the path to format as a tool option + * @return the option associated to this path type followed by the given path elements, + * or an empty string if there is no path element + * @throws IllegalStateException if no option is associated to this path type + */ + @Nonnull + @Override + public String option(final Iterable paths) { + return format(null, paths); + } + + /** + * Implementation shared with {@link Modular}. + */ + final String format(final String moduleName, final Iterable paths) { + if (option == null) { + throw new IllegalStateException("No option is associated to this path type."); + } + String prefix = (moduleName == null) ? (option + ' ') : (option + ' ' + moduleName + '='); + StringJoiner joiner = new StringJoiner(File.pathSeparator, prefix, ""); + joiner.setEmptyValue(""); + for (Path p : paths) { + joiner.add(p.toString()); + } + return joiner.toString(); + } + + @Override + public String toString() { + return "PathType[" + id() + "]"; + } + + /** + * Type of path which is applied to only one specific Java module. + * The main case is the Java {@code --patch-module} option. + * + * @see #PATCH_MODULE + * @see #patchModule(String) + */ + public final class Modular implements PathType { + /** + * Name of the module for which a path is specified. + */ + @Nonnull + private final String moduleName; + + /** + * Creates a new path type for the specified module. + * + * @param moduleName name of the module for which a path is specified + */ + private Modular(@Nonnull String moduleName) { + this.moduleName = Objects.requireNonNull(moduleName); + } + + @Override + public String id() { + return JavaPathType.this.name() + ":" + moduleName; + } + + /** + * Returns the type of path without indication about the target module. + * This is usually {@link #PATCH_MODULE}. + * + * @return type of path without indication about the target module + */ + @Nonnull + public JavaPathType rawType() { + return JavaPathType.this; + } + + /** + * Returns the name of the tool option for this path, not including the module name. + * + * @return name of the tool option for this path, not including the module name + */ + @Nonnull + public String name() { + return JavaPathType.this.name(); + } + + /** + * Returns the name of the module for which a path is specified + * + * @return name of the module for which a path is specified + */ + @Nonnull + public String moduleName() { + return moduleName; + } + + /** + * Returns the name of the tool option for this path. + * The option does not include the {@linkplain #moduleName() module name} on which it applies. + * + * @return the name of the tool option for this path type + */ + @Nonnull + @Override + public Optional option() { + return JavaPathType.this.option(); + } + + /** + * Returns the option followed by a string representation of the given path elements. + * The path elements are separated by an option-specific or platform-specific separator. + * If the given {@code paths} argument contains no element, then this method returns an empty string. + * + * @param paths the path to format as a string + * @return the option associated to this path type followed by the given path elements, + * or an empty string if there is no path element. + */ + @Nonnull + @Override + public String option(Iterable paths) { + return format(moduleName, paths); + } + + /** + * Returns the programmatic name of this path type, including the module to patch. + * For example, if this type was created by {@code JavaPathType.patchModule("foo.bar")}, + * then this method returns {@code "PathType[PATCH_MODULE:foo.bar]")}. + * + * @return the programmatic name together with the module name on which it applies + */ + @Nonnull + @Override + public String toString() { + return "PathType[" + id() + "]"; + } + } +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java new file mode 100644 index 000000000000..7a558081af1d --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java @@ -0,0 +1,102 @@ +/* + * 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.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. + * Path types are often exclusive. For example, a dependency should not be + * both on the Java class-path and on the Java module-path. + * + * @see org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths() + * + * @since 4.0.0 + */ +@Experimental +public interface PathType { + /** + * Returns the unique name of this path type, including the module to patch if any. + * For example, if this type is {@link JavaPathType#MODULES}, then this method returns {@code "MODULES"}. + * But if this type was created by {@code JavaPathType.patchModule("foo.bar")}, then this method returns + * {@code "PATCH_MODULE:foo.bar"}. + * + * @return the programmatic name together with the module name on which it applies + * @see #toString() + */ + @Nonnull + String id(); + + /** + * Returns the name of the tool option for this path. For example, if this path type + * is {@link JavaPathType#MODULES}, then this method returns {@code "--module-path"}. + * The option does not include the {@linkplain JavaPathType.Modular#moduleName() module name} + * on which it applies. + * + * @return the name of the tool option for this path type + */ + @Nonnull + Optional option(); + + /** + * Returns the option followed by a string representation of the given path elements. + * The path elements are separated by an option-specific or platform-specific separator. + * If the given {@code paths} argument contains no element, then this method returns an empty string. + * + *

          Examples: + * If {@code paths} is a list containing two elements, {@code path1} and {@code path2}, then: + *

          + *
            + *
          • If this type is {@link JavaPathType#MODULES}, then this method returns + * {@code "--module-path path1:path2"} on Unix or {@code "--module-path path1;path2"} on Windows.
          • + *
          • If this type was created by {@code JavaPathType.patchModule("foo.bar")}, then the method returns + * {@code "--patch-module foo.bar=path1:path2"} on Unix or {@code "--patch-module foo.bar=path1;path2"} + * on Windows.
          • + *
          + * + * @param paths the path to format as a string + * @return the option associated to this path type followed by the given path elements, + * or an empty string if there is no path element. + */ + @Nonnull + String option(Iterable paths); + + /** + * Returns the name of this path type. For example, if this path type + * is {@link JavaPathType#MODULES}, then this method returns {@code "MODULES"}. + * + * @return the programmatic name of this path type + */ + @Nonnull + String name(); + + /** + * Returns a string representation for this extensible enum describing a path type. + * For example {@code "PathType[PATCH_MODULE:foo.bar]"}. + */ + @Nonnull + @Override + String toString(); +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java index 45a46fd1a1ca..4842ae5d46a8 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java @@ -18,6 +18,8 @@ */ package org.apache.maven.api; +import java.util.Set; + import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Immutable; import org.apache.maven.api.annotations.Nonnull; @@ -30,7 +32,7 @@ *

          * It provides information about the file type (or extension) of the associated artifact, * its default classifier, and how the artifact will be used in the build when creating - * various build paths. + * class-paths or module-paths. *

          * For example, the type {@code java-source} has a {@code jar} extension and a * {@code sources} classifier. The artifact and its dependencies should be added @@ -41,6 +43,55 @@ @Experimental @Immutable public interface Type extends ExtensibleEnum { + /** + * Artifact type name for a POM file. + */ + String POM = "pom"; + + /** + * Artifact type name for a JAR file that can be placed either on the class-path or on the module-path. + * The path (classes or modules) is chosen by the plugin, possibly using heuristic rules. + * This is the behavior of Maven 3. + */ + String JAR = "jar"; + + /** + * Artifact type name for a JAR file to unconditionally place on the class-path. + * If the JAR is modular, its module information are ignored. + * This type is new in Maven 4. + */ + String CLASSPATH_JAR = "classpath-jar"; + + /** + * Artifact type name for a JAR file to unconditionally place on the module-path. + * If the JAR is not modular, then it is loaded by Java as an unnamed module. + * This type is new in Maven 4. + */ + String MODULAR_JAR = "modular-jar"; + + /** + * Artifact type name for source code packaged in a JAR file. + */ + String JAVA_SOURCE = "java-source"; + + /** + * Artifact type name for javadoc packaged in a JAR file. + */ + String JAVADOC = "javadoc"; + + /** + * Artifact type name for a Maven plugin. + */ + String MAVEN_PLUGIN = "maven-plugin"; + + /** + * Artifact type name for a JAR file containing test classes. If the main artifact is placed on the class-path + * ({@value #JAR} or {@value #CLASSPATH_JAR} types), then the test artifact will also be placed on the class-path. + * Otherwise, if the main artifact is placed on the module-path ({@value #JAR} or {@value #MODULAR_JAR} types), + * then the test artifact will be added using {@code --patch-module} option. + */ + String TEST_JAR = "test-jar"; + /** * Returns the dependency type id. * The id uniquely identifies this dependency type. @@ -76,13 +127,6 @@ public interface Type extends ExtensibleEnum { @Nullable String getClassifier(); - /** - * Specifies if the artifact should be added to the build path. - * - * @return if the artifact should be added to the build path - */ - boolean isBuildPathConstituent(); - /** * Specifies if the artifact already embeds its own dependencies. * This is the case for JEE packages or similar artifacts such as @@ -91,4 +135,19 @@ public interface Type extends ExtensibleEnum { * @return if the artifact's dependencies are included in the artifact */ boolean isIncludesDependencies(); + + /** + * 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. + * + *

          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}.

          + */ + @Nonnull + Set getPathTypes(); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java index 6d8f00935379..c0aa94ee194a 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java @@ -20,10 +20,13 @@ import java.util.Collection; import java.util.List; +import java.util.function.Predicate; import org.apache.maven.api.Artifact; import org.apache.maven.api.DependencyCoordinate; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.PathScope; +import org.apache.maven.api.PathType; import org.apache.maven.api.Project; import org.apache.maven.api.Session; import org.apache.maven.api.annotations.Experimental; @@ -37,6 +40,16 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest { @Nonnull PathScope getPathScope(); + /** + * Returns a filter for the types of path (class-path, module-path, …) accepted by the tool. + * For example, if a Java tools accepts only class-path elements, then the filter should return + * {@code true} for {@link JavaPathType#CLASSES} and {@code false} for {@link JavaPathType#MODULES}. + * If no filter is explicitly set, then the default is a filter accepting everything. + * + * @return a filter for the types of path (class-path, module-path, …) accepted by the tool + */ + Predicate getPathTypeFilter(); + @Nonnull static DependencyResolverRequestBuilder builder() { return new DependencyResolverRequestBuilder(); @@ -88,6 +101,8 @@ static DependencyResolverRequest build(Session session, List pathTypeFilter; + @Nonnull @Override public DependencyResolverRequestBuilder session(@Nonnull Session session) { @@ -158,16 +173,32 @@ public DependencyResolverRequestBuilder pathScope(@Nonnull PathScope pathScope) return this; } + @Nonnull + public DependencyResolverRequestBuilder pathTypeFilter(@Nonnull Predicate pathTypeFilter) { + this.pathTypeFilter = pathTypeFilter; + return this; + } + @Override public DependencyResolverRequest build() { return new DefaultDependencyResolverRequest( - session, project, rootArtifact, root, dependencies, managedDependencies, verbose, pathScope); + session, + project, + rootArtifact, + root, + dependencies, + managedDependencies, + verbose, + pathScope, + pathTypeFilter); } static class DefaultDependencyResolverRequest extends DefaultDependencyCollectorRequest implements DependencyResolverRequest { private final PathScope pathScope; + private final Predicate pathTypeFilter; + DefaultDependencyResolverRequest( Session session, Project project, @@ -176,9 +207,11 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector Collection dependencies, Collection managedDependencies, boolean verbose, - PathScope pathScope) { + PathScope pathScope, + Predicate pathTypeFilter) { super(session, project, rootArtifact, root, dependencies, managedDependencies, verbose); this.pathScope = nonNull(pathScope, "pathScope cannot be null"); + this.pathTypeFilter = (pathTypeFilter != null) ? pathTypeFilter : (t) -> true; if (verbose) { throw new IllegalArgumentException("verbose cannot be true for resolving dependencies"); } @@ -189,6 +222,11 @@ static class DefaultDependencyResolverRequest extends DefaultDependencyCollector public PathScope getPathScope() { return pathScope; } + + @Override + public Predicate getPathTypeFilter() { + return pathTypeFilter; + } } } } 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 793243850068..60468046145e 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 @@ -21,9 +21,11 @@ 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.Node; +import org.apache.maven.api.PathType; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; @@ -32,13 +34,57 @@ public interface DependencyResolverResult extends DependencyCollectorResult { /** * The ordered list of the flattened dependency nodes. + * + * @return the ordered list of the flattened dependency nodes */ @Nonnull List getNodes(); + /** + * Returns the file paths of all dependencies, regardless on which tool option those paths should be placed. + * The returned list may contain a mix of Java class-path, Java module-path, and other types of path elements. + * + * @return the paths of all dependencies + */ @Nonnull List getPaths(); + /** + * Returns the file paths of all dependencies, dispatched according the tool options where to place them. + * The {@link PathType} keys identify, for example, {@code --class-path} or {@code --module-path} options. + * In the case of Java tools, the map may also contain {@code --patch-module} options, which are + * {@linkplain org.apache.maven.api.JavaPathType#patchModule(String) handled in a special way}. + * + *

          Design note: + * All types of path are determined together because they are sometime mutually exclusive. + * For example, an artifact of type {@value org.apache.maven.api.Type#JAR} can be placed + * either on the class-path or on the module-path. The project needs to make a choice + * (possibly using heuristic rules), then to add the dependency in only one of the options + * identified by {@link PathType}.

          + * + * @return file paths to place on the different tool options + */ + @Nonnull + Map> getDispatchedPaths(); + @Nonnull Map getDependencies(); + + /** + * Formats the command-line option for the path of the specified type. + * The option are documented in {@link org.apache.maven.api.JavaPathType} enumeration values. + * + * @param type the desired type of path (class-path, module-path, …) + * @return the option to pass to Java tools + */ + default Optional formatOption(final PathType type) { + List paths = getDispatchedPaths().get(type); + if (paths != null) { + String option = type.option(paths); + if (!option.isEmpty()) { + return Optional.of(option); + } + } + return Optional.empty(); + } } diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java index 9a1ca1f4336b..44f2615790ca 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java @@ -181,52 +181,64 @@ private boolean empty(String value) { return (value == null) || (value.trim().length() < 1); } + @Override public String getClassifier() { return classifier; } + @Override public boolean hasClassifier() { return classifier != null && !classifier.isEmpty(); } + @Override public String getScope() { return scope; } + @Override public String getGroupId() { return groupId; } + @Override public String getArtifactId() { return artifactId; } + @Override public String getVersion() { return version; } + @Override public void setVersion(String version) { this.version = version; setBaseVersionInternal(version); versionRange = null; } + @Override public String getType() { return type; } + @Override public void setFile(File file) { this.file = file; } + @Override public File getFile() { return file; } + @Override public ArtifactRepository getRepository() { return repository; } + @Override public void setRepository(ArtifactRepository repository) { this.repository = repository; } @@ -235,10 +247,12 @@ public void setRepository(ArtifactRepository repository) { // // ---------------------------------------------------------------------- + @Override public String getId() { return getDependencyConflictId() + ":" + getBaseVersion(); } + @Override public String getDependencyConflictId() { StringBuilder sb = new StringBuilder(128); sb.append(getGroupId()); @@ -257,6 +271,7 @@ private void appendArtifactTypeClassifierString(StringBuilder sb) { } } + @Override public void addMetadata(ArtifactMetadata metadata) { if (metadataMap == null) { metadataMap = new HashMap<>(); @@ -270,6 +285,7 @@ public void addMetadata(ArtifactMetadata metadata) { } } + @Override public Collection getMetadataList() { if (metadataMap == null) { return Collections.emptyList(); @@ -282,6 +298,7 @@ public Collection getMetadataList() { // Object overrides // ---------------------------------------------------------------------- + @Override public String toString() { StringBuilder sb = new StringBuilder(); if (getGroupId() != null) { @@ -323,6 +340,7 @@ public int hashCode() { return Objects.hash(groupId, artifactId, type, classifier, version); } + @Override public String getBaseVersion() { if (baseVersion == null && version != null) { setBaseVersionInternal(version); @@ -339,6 +357,7 @@ protected String getBaseVersionInternal() { return baseVersion; } + @Override public void setBaseVersion(String baseVersion) { setBaseVersionInternal(baseVersion); } @@ -347,6 +366,7 @@ protected void setBaseVersionInternal(String baseVersion) { this.baseVersion = ArtifactUtils.toSnapshotVersion(baseVersion); } + @Override public int compareTo(Artifact a) { int result = groupId.compareTo(a.getGroupId()); if (result == 0) { @@ -376,47 +396,58 @@ public int compareTo(Artifact a) { return result; } + @Override public void updateVersion(String version, ArtifactRepository localRepository) { setResolvedVersion(version); setFile(new File(localRepository.getBasedir(), localRepository.pathOf(this))); } + @Override public String getDownloadUrl() { return downloadUrl; } + @Override public void setDownloadUrl(String downloadUrl) { this.downloadUrl = downloadUrl; } + @Override public ArtifactFilter getDependencyFilter() { return dependencyFilter; } + @Override public void setDependencyFilter(ArtifactFilter artifactFilter) { dependencyFilter = artifactFilter; } + @Override public ArtifactHandler getArtifactHandler() { return artifactHandler; } + @Override public List getDependencyTrail() { return dependencyTrail; } + @Override public void setDependencyTrail(List dependencyTrail) { this.dependencyTrail = dependencyTrail; } + @Override public void setScope(String scope) { this.scope = scope; } + @Override public VersionRange getVersionRange() { return versionRange; } + @Override public void setVersionRange(VersionRange versionRange) { this.versionRange = versionRange; selectVersionFromNewRangeIfAvailable(); @@ -431,70 +462,86 @@ private void selectVersionFromNewRangeIfAvailable() { } } + @Override public void selectVersion(String version) { this.version = version; setBaseVersionInternal(version); } + @Override public void setGroupId(String groupId) { this.groupId = groupId; } + @Override public void setArtifactId(String artifactId) { this.artifactId = artifactId; } + @Override public boolean isSnapshot() { return getBaseVersion() != null && (getBaseVersion().endsWith(SNAPSHOT_VERSION) || getBaseVersion().equals(LATEST_VERSION)); } + @Override public void setResolved(boolean resolved) { this.resolved = resolved; } + @Override public boolean isResolved() { return resolved; } + @Override public void setResolvedVersion(String version) { this.version = version; // retain baseVersion } + @Override public void setArtifactHandler(ArtifactHandler artifactHandler) { this.artifactHandler = artifactHandler; } + @Override public void setRelease(boolean release) { this.release = release; } + @Override public boolean isRelease() { return release; } + @Override public List getAvailableVersions() { return availableVersions; } + @Override public void setAvailableVersions(List availableVersions) { this.availableVersions = availableVersions; } + @Override public boolean isOptional() { return optional; } + @Override public ArtifactVersion getSelectedVersion() throws OverConstrainedVersionException { return versionRange.getSelectedVersion(this); } + @Override public boolean isSelectedVersionKnown() throws OverConstrainedVersionException { return versionRange.isSelectedVersionKnown(this); } + @Override public void setOptional(boolean optional) { this.optional = optional; } diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java b/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java index 364e12425ee8..12f50ef31a76 100644 --- a/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java +++ b/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java @@ -54,8 +54,15 @@ public interface ArtifactHandler { String getLanguage(); /** - * IMPORTANT: this is WRONGLY NAMED method (and/or remnant for Maven2). - * Its meaning is "is added to build path", that is used to create classpath/modulepath/etc. + * Specifies if the artifact contains java classes and can be added to the classpath. + * Whether the artifact should be added to the classpath depends on other + * dependency properties. + * + * @return if the artifact can be added to the class path + * + * @deprecated A value of {@code true} does not mean that the dependency should + * be placed on the classpath. See {@code JavaPathType} instead for better analysis. */ + @Deprecated boolean isAddedToClasspath(); } diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java b/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java index deb3e77c5456..f70db5bcbd32 100644 --- a/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java +++ b/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java @@ -27,6 +27,7 @@ public void setExtension(String extension) { this.extension = extension; } + @Override public String getExtension() { return extension; } @@ -35,6 +36,7 @@ public void setDirectory(String directory) { this.directory = directory; } + @Override public String getDirectory() { return directory; } @@ -43,6 +45,7 @@ public void setClassifier(String classifier) { this.classifier = classifier; } + @Override public String getClassifier() { return classifier; } @@ -51,6 +54,7 @@ public void setPackaging(String packaging) { this.packaging = packaging; } + @Override public String getPackaging() { return packaging; } @@ -59,6 +63,7 @@ public void setIncludesDependencies(boolean includesDependencies) { this.includesDependencies = includesDependencies; } + @Override public boolean isIncludesDependencies() { return includesDependencies; } @@ -67,14 +72,18 @@ public void setLanguage(String language) { this.language = language; } + @Override public String getLanguage() { return language; } + @Deprecated public void setAddedToClasspath(boolean addedToClasspath) { this.addedToClasspath = addedToClasspath; } + @Override + @Deprecated public boolean isAddedToClasspath() { return addedToClasspath; } diff --git a/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java b/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java index 860fbe3fb528..93c90bd889fa 100644 --- a/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java +++ b/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java @@ -39,30 +39,38 @@ public TestArtifactHandler(String type, String extension) { this.extension = extension; } + @Override public String getClassifier() { return null; } + @Override public String getDirectory() { return getPackaging() + "s"; } + @Override public String getExtension() { return extension; } + @Override public String getLanguage() { return "java"; } + @Override public String getPackaging() { return type; } + @Override + @Deprecated public boolean isAddedToClasspath() { return true; } + @Override public boolean isIncludesDependencies() { return false; } diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java index 0a083732c05d..198fe6fb6aa3 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java @@ -37,6 +37,7 @@ public class DefaultArtifactHandler implements ArtifactHandler { private String language; + @Deprecated private boolean addedToClasspath; /** @@ -146,10 +147,12 @@ public void setLanguage(final String language) { } @Override + @Deprecated public boolean isAddedToClasspath() { return addedToClasspath; } + @Deprecated public void setAddedToClasspath(final boolean addedToClasspath) { this.addedToClasspath = addedToClasspath; } diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java index 3a0c1a234f8f..2ad0541914dc 100644 --- a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java +++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java @@ -26,6 +26,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Type; import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.artifact.handler.ArtifactHandler; @@ -60,6 +61,7 @@ public void onEvent(Object event) { } } + @Override public ArtifactHandler getArtifactHandler(String id) { return allHandlers.computeIfAbsent(id, k -> { Type type = typeRegistry.require(id); @@ -71,7 +73,8 @@ public ArtifactHandler getArtifactHandler(String id) { null, type.isIncludesDependencies(), type.getLanguage().id(), - type.isBuildPathConstituent()); + type.getPathTypes().contains(JavaPathType.CLASSES)); + // TODO: watch out for module path }); // Note: here, type decides is artifact added to "build path" (for example during resolution) @@ -79,6 +82,7 @@ public ArtifactHandler getArtifactHandler(String id) { // but to create those, proper filtering should happen via Type properties. } + @Override public void addHandlers(Map handlers) { throw new UnsupportedOperationException("Adding handlers programmatically is not supported anymore"); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java index e06dd9e13cb1..d3861f2c571c 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java +++ b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java @@ -18,6 +18,7 @@ */ package org.apache.maven.internal.aether; +import org.apache.maven.api.PathType; import org.apache.maven.api.Type; import org.apache.maven.api.services.TypeRegistry; import org.apache.maven.internal.impl.DefaultType; @@ -45,8 +46,8 @@ public ArtifactType get(String typeId) { type.getLanguage(), type.getExtension(), type.getClassifier(), - type.isBuildPathConstituent(), - type.isIncludesDependencies()); + type.isIncludesDependencies(), + type.getPathTypes().toArray(new PathType[0])); } return null; } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java index 5a5b3f9b0515..8137a2e2c968 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java @@ -34,6 +34,7 @@ import static org.apache.maven.internal.impl.Utils.nonNull; public class DefaultDependency implements Dependency { + private final InternalSession session; private final org.eclipse.aether.graph.Dependency dependency; private final String key; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java index 298576d5f4b6..65a1a18ea05f 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java @@ -21,19 +21,26 @@ import javax.inject.Named; import javax.inject.Singleton; +import java.io.IOException; import java.nio.file.Path; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.maven.api.*; +import org.apache.maven.api.Artifact; +import org.apache.maven.api.ArtifactCoordinate; +import org.apache.maven.api.Dependency; +import org.apache.maven.api.Node; +import org.apache.maven.api.PathType; +import org.apache.maven.api.Project; +import org.apache.maven.api.Session; import org.apache.maven.api.services.*; import org.apache.maven.lifecycle.LifecycleExecutionException; import org.apache.maven.lifecycle.internal.LifecycleDependencyResolver; @@ -69,59 +76,69 @@ private static DependencyFilter getScopeDependencyFilter(PathScope scope) { }; } + /** + * Collects, flattens and resolves the dependencies. + * + * @param request the request to resolve + * @return the result of the resolution + */ @Override - public DependencyResolverResult resolve(DependencyResolverRequest request) + public DependencyResolverResult resolve(final DependencyResolverRequest request) throws DependencyCollectorException, DependencyResolverException, ArtifactResolverException { - nonNull(request, "request can not be null"); - InternalSession session = InternalSession.from(request.getSession()); - + nonNull(request, "request"); + final InternalSession session = InternalSession.from(request.getSession()); + final Predicate filter = request.getPathTypeFilter(); + final PathModularizationCache cache = new PathModularizationCache(); // TODO: should be project-wide cache. if (request.getProject().isPresent()) { - DependencyResolutionResult result = resolveDependencies( + final DependencyResolutionResult resolved = resolveDependencies( request.getSession(), request.getProject().get(), request.getPathScope()); - Map nodes = stream( - result.getDependencyGraph()) + final Map nodes = stream( + resolved.getDependencyGraph()) .filter(n -> n.getDependency() != null) .collect(Collectors.toMap(DependencyNode::getDependency, n -> n)); - Node root = session.getNode(result.getDependencyGraph()); - List dependencies = new ArrayList<>(); - Map artifacts = new LinkedHashMap<>(); - List paths = new ArrayList<>(); - for (org.eclipse.aether.graph.Dependency dep : result.getResolvedDependencies()) { - dependencies.add(session.getNode(nodes.get(dep))); + final Node root = session.getNode(resolved.getDependencyGraph()); + final List deprendencies = resolved.getResolvedDependencies(); + final DefaultDependencyResolverResult result = + new DefaultDependencyResolverResult(resolved.getCollectionErrors(), root, deprendencies.size()); + for (org.eclipse.aether.graph.Dependency dep : deprendencies) { + Node node = session.getNode(nodes.get(dep)); Path path = dep.getArtifact().getFile().toPath(); - artifacts.put(session.getDependency(dep), path); - paths.add(path); + try { + result.addDependency(node, session.getDependency(dep), filter, path, cache); + } catch (IOException e) { + throw cannotReadModuleInfo(path, e); + } } - return new DefaultDependencyResolverResult( - result.getCollectionErrors(), root, dependencies, paths, artifacts); + return result; } - DependencyCollectorResult collectorResult = + final DependencyCollectorResult collectorResult = session.getService(DependencyCollector.class).collect(request); - List nodes = flatten(session, collectorResult.getRoot(), request.getPathScope()); - List deps = - nodes.stream().map(Node::getDependency).filter(Objects::nonNull).collect(Collectors.toList()); - List coordinates = - deps.stream().map(Artifact::toCoordinate).collect(Collectors.toList()); - Map artifacts = session.resolveArtifacts(coordinates); - Map dependencies = new LinkedHashMap<>(); - List paths = new ArrayList<>(); - for (Dependency d : deps) { - Path path = artifacts.get(d); - if (dependencies.put(d, path) != null) { - throw new IllegalStateException("Duplicate key"); + final List nodes = flatten(session, collectorResult.getRoot(), request.getPathScope()); + final List coordinates = nodes.stream() + .map(Node::getDependency) + .filter(Objects::nonNull) + .map(Artifact::toCoordinate) + .collect(Collectors.toList()); + final Map artifacts = session.resolveArtifacts(coordinates); + final DefaultDependencyResolverResult result = new DefaultDependencyResolverResult( + collectorResult.getExceptions(), collectorResult.getRoot(), nodes.size()); + for (Node node : nodes) { + Dependency d = node.getDependency(); + Path path = (d != null) ? artifacts.get(d) : null; + try { + result.addDependency(node, d, filter, path, cache); + } catch (IOException e) { + throw cannotReadModuleInfo(path, e); } - paths.add(path); } - - return new DefaultDependencyResolverResult( - collectorResult.getExceptions(), collectorResult.getRoot(), nodes, paths, dependencies); + return result; } - private Stream stream(DependencyNode node) { - return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(this::stream)); + private static Stream stream(final DependencyNode node) { + return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(DefaultDependencyResolver::stream)); } private DependencyResolutionResult resolveDependencies(Session session, Project project, PathScope scope) { @@ -141,7 +158,7 @@ private DependencyResolutionResult resolveDependencies(Session session, Project } } - private MavenProject getMavenProject(Project project) { + private static MavenProject getMavenProject(final Project project) { return ((DefaultProject) project).getProject(); } @@ -149,49 +166,7 @@ private Collection toScopes(PathScope scope) { return map(scope.dependencyScopes(), DependencyScope::id); } - static class DefaultDependencyResolverResult implements DependencyResolverResult { - private final List exceptions; - private final Node root; - private final List nodes; - private final List paths; - private final Map dependencies; - - DefaultDependencyResolverResult( - List exceptions, - Node root, - List nodes, - List paths, - Map dependencies) { - this.exceptions = exceptions; - this.root = root; - this.nodes = nodes; - this.paths = paths; - this.dependencies = dependencies; - } - - @Override - public List getExceptions() { - return exceptions; - } - - @Override - public Node getRoot() { - return root; - } - - @Override - public List getNodes() { - return nodes; - } - - @Override - public List getPaths() { - return paths; - } - - @Override - public Map getDependencies() { - return dependencies; - } + private static DependencyResolverException cannotReadModuleInfo(final Path path, final IOException cause) { + return new DependencyResolverException("Cannot read module information of " + path, cause); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java new file mode 100644 index 000000000000..2b2d6a8810bb --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java @@ -0,0 +1,352 @@ +/* + * 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.internal.impl; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +import org.apache.maven.api.Dependency; +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.Node; +import org.apache.maven.api.PathType; +import org.apache.maven.api.services.DependencyResolverRequest; +import org.apache.maven.api.services.DependencyResolverResult; + +/** + * The result of collecting dependencies with a dependency resolver. + * New instances are initially empty. Callers must populate with calls + * to the following methods, in that order: + * + *
            + *
          • {@link #addOutputDirectory(Path, Path, PathModularizationCache)} (optional)
          • + *
          • {@link #addDependency(Node, Dependency, Set, Path, PathModularizationCache)}
          • + *
          + * + * @see DefaultDependencyResolver#resolve(DependencyResolverRequest) + */ +final class DefaultDependencyResolverResult implements DependencyResolverResult { + /** + * The exceptions that occurred while building the dependency graph. + */ + private final List exceptions; + + /** + * The root node of the dependency graph. + */ + private final Node root; + + /** + * The ordered list of the flattened dependency nodes. + */ + private final List nodes; + + /** + * The file paths of all dependencies, regardless on which Java tool option those paths should be placed. + */ + private final List paths; + + /** + * The file paths of all dependencies, dispatched according the Java options where to place them. + */ + private final Map> dispatchedPaths; + + /** + * The dependencies together with the path to each dependency. + */ + private final Map dependencies; + + /** + * Information about modules in the main output. This field is initially null and is set to a non-null + * value when the output directories have been set, or when it is too late for setting them. + */ + private PathModularization outputModules; + + /** + * Creates an initially empty result. Callers should add path elements by calls + * to {@link #addDependency(Node, Dependency, Path, PathModularizationCache)}. + * + * @param exceptions the exceptions that occurred while building the dependency graph + * @param root the root node of the dependency graph + * @param count estimated number of dependencies + */ + DefaultDependencyResolverResult(final List exceptions, final Node root, final int count) { + this.exceptions = exceptions; + this.root = root; + nodes = new ArrayList<>(count); + paths = new ArrayList<>(count); + dispatchedPaths = new LinkedHashMap<>(); + dependencies = new LinkedHashMap<>(count + count / 3); + } + + /** + * Adds the given path element to the specified type of path. + * + * @param type the type of path (class-path, module-path, …) + * @param path the path element to add + */ + private void addPathElement(final PathType type, final Path path) { + dispatchedPaths.computeIfAbsent(type, (t) -> new ArrayList<>()).add(path); + } + + /** + * Adds main and test output directories to the result. This method adds the main output directory + * to the module-path if it contains a {@code module-info.class}, or to the class-path otherwise. + * For the test output directory, the rules are more complex and are governed by the fact that + * Java does not accept the placement of two modules of the same name on the module-path. + * So the modular test output directory usually needs to be placed in a {@code --path-module} option. + * + *
            + *
          • If the test output directory is modular, then: + *
              + *
            • If a test module name is identical to a main module name, + * place the test directory in a {@code --patch-module} option.
            • + *
            • Otherwise, place the test directory on the module-path. However, this case + * (a module existing only in test output, not in main output) should be uncommon.
            • + *
            + *
          • + *
          • Otherwise (test output contains no module information), then: + *
              + *
            • If the main output is on the module-path, place the test output + * on a {@code --patch-module} option.
            • + *
            • Otherwise (main output on the class-path), place the test output on the class-path too.
            • + *
            + *
          • + *
          + * + * This method must be invoked before {@link #addDependency(Node, Dependency, Path)} + * if output directories are desired on the class-path or module-path. + * This method can be invoked at most once. + * + * @param main the main output directory, or {@code null} if none + * @param test the test output directory, or {@code null} if none + * @param cache cache of module information about each dependency + * @throws IOException if an error occurred while reading module information + */ + void addOutputDirectory(final Path main, final Path test, final PathModularizationCache cache) throws IOException { + if (outputModules != null) { + throw new IllegalStateException("Output directories must be set first and only once."); + } + if (main != null) { + outputModules = cache.getModuleInfo(main); + addPathElement(outputModules.getPathType(), main); + } else { + outputModules = PathModularization.NONE; + } + if (test != null) { + boolean addToClasspath = true; + final PathModularization testModules = cache.getModuleInfo(test); + final boolean isModuleHierarchy = outputModules.isModuleHierarchy() || testModules.isModuleHierarchy(); + for (final String moduleName : outputModules.getModuleNames().values()) { + Path subdir = test; + if (isModuleHierarchy) { + // If module hierarchy is used, the directory names shall be the module names. + final Path path = test.resolve(moduleName); + if (!Files.isDirectory(path)) { + // Main module without tests. It is okay. + continue; + } + subdir = path; + } + // When the same module is found in main and test output, the latter is patching the former. + addPathElement(JavaPathType.patchModule(moduleName), subdir); + addToClasspath = false; + } + /* + * 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 (final Map.Entry entry : + testModules.getModuleNames().entrySet()) { + if (!outputModules.containsModule(entry.getValue())) { + addPathElement(JavaPathType.MODULES, entry.getKey()); + addToClasspath = false; + } + } + if (addToClasspath) { + addPathElement(JavaPathType.CLASSES, test); + } + } + } + + /** + * Adds a dependency to the result. This method populates the {@link #nodes}, {@link #paths}, + * {@link #dispatchedPaths} and {@link #dependencies} collections with the given arguments. + * + * @param node the dependency node + * @param dep the dependency for the given node, or {@code null} if none + * @param filter filter the paths accepted by the tool which will consume the path. + * @param path the path to the dependency, or {@code null} if the dependency was null + * @param cache cache of module information about each dependency + * @throws IOException if an error occurred while reading module information + */ + void addDependency( + final Node node, + final Dependency dep, + final Predicate filter, + final Path path, + final PathModularizationCache cache) + throws IOException { + nodes.add(node); + if (dep == null) { + return; + } + if (dependencies.put(dep, path) != null) { + throw new IllegalStateException("Duplicated key: " + dep); + } + if (path == null) { + return; + } + paths.add(path); + /* + * Dispatch the dependency to class-path, module-path, patch-module path, etc. + * according the dependency properties. We need to process patch-module first, + * because this type depends on whether a module of the same name has already + * been added on the module-type. + */ + // final DependencyProperties properties = dep.getDependencyProperties(); + final Set pathTypes = dep.getType().getPathTypes(); + if (containsPatches(pathTypes)) { + if (outputModules == null) { + // For telling users that it is too late for setting the output directory. + outputModules = PathModularization.NONE; + } + PathType type = null; + for (Map.Entry info : + cache.getModuleInfo(path).getModuleNames().entrySet()) { + String moduleName = info.getValue(); + type = JavaPathType.patchModule(moduleName); + if (!containsModule(moduleName, cache)) { + /* + * Not patching an existing module. This case should be unusual. If it nevertheless + * happens, add on class-path or module-path if allowed, or keep patching otherwise. + * The latter case (keep patching) is okay if the main module will be defined later. + */ + type = cache.selectPathType(pathTypes, filter, path).orElse(type); + } + addPathElement(type, info.getKey()); + // There is usually no more than one element, but nevertheless allow multi-modules. + } + /* + * If the dependency has no module information, search for an artifact of the same groupId + * and artifactId. If one is found, we are patching that module. If none is found, add the + * dependency as a normal dependency. + */ + if (type == null) { + Path main = findArtifactPath(dep.getGroupId(), dep.getArtifactId()); + if (main != null) { + for (Map.Entry info : + cache.getModuleInfo(main).getModuleNames().entrySet()) { + type = JavaPathType.patchModule(info.getValue()); + addPathElement(type, info.getKey()); + // There is usually no more than one element, but nevertheless allow multi-modules. + } + } + } + if (type != null) { + return; // Dependency added, we are done. + } + } + cache.selectPathType(pathTypes, filter, path).ifPresent((type) -> addPathElement(type, path)); + } + + /** + * Returns whether the given set of path types contains at least one patch for a module. + */ + private boolean containsPatches(final Set types) { + for (PathType type : types) { + if (type instanceof JavaPathType.Modular) { + type = ((JavaPathType.Modular) type).rawType(); + } + if (JavaPathType.PATCH_MODULE.equals(type)) { + return true; + } + } + return false; + } + + /** + * Returns whether at least one previously added modular dependency contains a module of the given name. + * + * @param moduleName name of the module to search + * @param cache cache of module information about each dependency + */ + private boolean containsModule(final String moduleName, final PathModularizationCache cache) throws IOException { + for (Path path : dispatchedPaths.getOrDefault(JavaPathType.MODULES, Collections.emptyList())) { + if (cache.getModuleInfo(path).containsModule(moduleName)) { + return true; + } + } + return false; + } + + /** + * Searches an artifact of the given group and artifact identifiers, and returns its path + * + * @param group the group identifier to search + * @param artifact the artifact identifier to search + * @return path to the desired artifact, or {@code null} if not found + */ + private Path findArtifactPath(final String group, final String artifact) throws IOException { + for (final Map.Entry entry : dependencies.entrySet()) { + Dependency dep = entry.getKey(); + if (group.equals(dep.getGroupId()) && artifact.equals(dep.getArtifactId())) { + return entry.getValue(); + } + } + return null; + } + + @Override + public List getExceptions() { + return exceptions; + } + + @Override + public Node getRoot() { + return root; + } + + @Override + public List getNodes() { + return nodes; + } + + @Override + public List getPaths() { + return paths; + } + + @Override + public Map> getDispatchedPaths() { + return dispatchedPaths; + } + + @Override + public Map getDependencies() { + return dependencies; + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java index 9dca04e0ea35..cc5534f4cdb1 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java @@ -18,11 +18,12 @@ */ package org.apache.maven.internal.impl; -import java.util.Collections; -import java.util.HashMap; +import java.util.*; import java.util.Map; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Language; +import org.apache.maven.api.PathType; import org.apache.maven.api.Type; import org.eclipse.aether.artifact.ArtifactProperties; import org.eclipse.aether.artifact.ArtifactType; @@ -37,22 +38,22 @@ public class DefaultType implements Type, ArtifactType { private final String extension; private final String classifier; - private final boolean buildPathConstituent; private final boolean includesDependencies; + private final Set pathTypes; public DefaultType( String id, Language language, String extension, String classifier, - boolean buildPathConstituent, - boolean includesDependencies) { + boolean includesDependencies, + PathType... pathTypes) { this.id = nonNull(id, "id"); this.language = nonNull(language, "language"); this.extension = nonNull(extension, "extension"); this.classifier = classifier; - this.buildPathConstituent = buildPathConstituent; this.includesDependencies = includesDependencies; + this.pathTypes = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(pathTypes))); } @Override @@ -80,23 +81,23 @@ public String getClassifier() { return classifier; } - @Override - public boolean isBuildPathConstituent() { - return this.buildPathConstituent; - } - @Override public boolean isIncludesDependencies() { return this.includesDependencies; } + public Set getPathTypes() { + return this.pathTypes; + } + @Override public Map getProperties() { Map properties = new HashMap<>(); properties.put(ArtifactProperties.TYPE, this.id); properties.put(ArtifactProperties.LANGUAGE, this.language.id()); properties.put(ArtifactProperties.INCLUDES_DEPENDENCIES, String.valueOf(includesDependencies)); - properties.put(ArtifactProperties.CONSTITUTES_BUILD_PATH, String.valueOf(buildPathConstituent)); + properties.put( + ArtifactProperties.CONSTITUTES_BUILD_PATH, String.valueOf(pathTypes.contains(JavaPathType.CLASSES))); return Collections.unmodifiableMap(properties); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java index faf8d4ca9391..0a74fa7f0489 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java @@ -92,8 +92,9 @@ public Type require(String id) { languageRegistry.require(handler.getLanguage()), handler.getExtension(), handler.getClassifier(), - handler.isAddedToClasspath(), - handler.isIncludesDependencies()); + handler.isIncludesDependencies() + // TODO: add path types + ); }); } return type; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java new file mode 100644 index 000000000000..631f8344c254 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java @@ -0,0 +1,265 @@ +/* + * 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.internal.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; + +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.annotations.Nonnull; + +/** + * Information about the modules contained in a path element. + * The path element may be a JAR file or a directory. Directories may use either package hierarchy + * or module hierarchy, but not module source hierarchy. The latter is excluded because this class + * is for path elements of compiled codes. + */ +final class PathModularization { + /** + * A unique constant for all non-modular dependencies. + */ + public static final PathModularization NONE = new PathModularization(); + + /** + * Name of the file to use as a sentinel value for deciding if a directory or a JAR is modular. + */ + private static final String MODULE_INFO = "module-info.class"; + + /** + * The attribute for automatic module name in {@code META-INF/MANIFEST.MF} files. + */ + private static final Attributes.Name AUTO_MODULE_NAME = new Attributes.Name("Automatic-Module-Name"); + + /** + * Module information 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. + * + *

          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.

          + * + * @see #getModuleNames() + */ + private final Map 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; + + /** + * Constructs an empty instance for non-modular dependencies. + * + * @see #NONE + */ + private PathModularization() { + descriptors = Collections.emptyMap(); + isModuleHierarchy = false; + } + + /** + * Finds module information in the given JAR file, output directory, or test output directory. + * If no module is found, or if module information cannot be extracted, then this constructor + * builds an empty map. + * + *

          If the {@code resolve} parameter value is {@code false}, then some or all map values may + * be null instead of the actual module name. This option can avoid the cost of reading module + * descriptors when only the modules existence needs to be verified.

          + * + *

          Algorithm: + * If the given path is a directory, then there is a choice: + *

          + *
            + *
          • Package hierarchy: if a {@code module-info.class} file is found at the root, + * then builds a singleton map with the module name declared in that descriptor.
          • + *
          • Module hierarchy: if {@code module-info.class} files are found in sub-directories, + * at a deep intentionally restricted to one level, then builds a map of module names found + * in the descriptor of each sub-directory.
          • + *
          + * + * Otherwise if the given path is a JAR file, then there is a choice: + *
            + *
          • If a {@code module-info.class} file is found in the root directory or in a + * {@code "META-INF/versions/{n}/"} subdirectory, builds a singleton map with + * the module name declared in that descriptor.
          • + *
          • Otherwise if an {@code "Automatic-Module-Name"} attribute is declared in the + * {@code META-INF/MANIFEST.MF} file, builds a singleton map with the value of that attribute.
          • + *
          + * + * Otherwise builds an empty map. + * + * @param path directory or JAR file to test + * @param resolve whether the module names are requested. If false, null values may be used instead + * @throws IOException if an error occurred while reading the JAR file or the module descriptor + */ + PathModularization(final Path path, final boolean resolve) throws IOException { + if (Files.isDirectory(path)) { + /* + * Package hierarchy: only one module with descriptor at the root. + * This is the layout of output directories in projects using the + * classical (Java 8 and before) way to organize source files. + */ + Path file = path.resolve(MODULE_INFO); + if (Files.isRegularFile(file)) { + String name = null; + if (resolve) { + try (InputStream in = Files.newInputStream(file)) { + name = getModuleName(in); + } + } + descriptors = Collections.singletonMap(file, name); + isModuleHierarchy = false; + return; + } + /* + * Module hierarchy: many modules, one per directory, with descriptor at the root of the sub-directory. + * This is the layout of output directories in projects using the new (Java 9 and later) way to organize + * source files. + */ + if (Files.isDirectory(file)) { + final Map names = new HashMap<>(); + try (Stream subdirs = Files.list(file)) { + subdirs.filter(Files::isDirectory).forEach((subdir) -> { + Path mf = subdir.resolve(MODULE_INFO); + if (Files.isRegularFile(mf)) { + String name = null; + if (resolve) { + try (InputStream in = Files.newInputStream(mf)) { + name = getModuleName(in); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + names.put(mf, name); + } + }); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + if (!names.isEmpty()) { + descriptors = Collections.unmodifiableMap(names); + isModuleHierarchy = true; + return; + } + } + } else if (Files.isRegularFile(path)) { + /* + * JAR file: can contain only one module, with descriptor at the root. + * If no descriptor, the "Automatic-Module-Name" manifest attribute is + * taken as a fallback. + */ + try (JarFile jar = new JarFile(path.toFile())) { + final ZipEntry entry = jar.getEntry(MODULE_INFO); + if (entry != null) { + String name = null; + if (resolve) { + try (InputStream in = jar.getInputStream(entry)) { + name = getModuleName(in); + } + } + descriptors = Collections.singletonMap(path, name); + isModuleHierarchy = false; + return; + } + // No module descriptor, check manifest file. + final Manifest mf = jar.getManifest(); + if (mf != null) { + final Object name = mf.getMainAttributes().get(AUTO_MODULE_NAME); + if (name instanceof String) { + descriptors = Collections.singletonMap(path, (String) name); + isModuleHierarchy = false; + return; + } + } + } + } + descriptors = Collections.emptyMap(); + isModuleHierarchy = false; + } + + /** + * Returns 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(final InputStream in) throws IOException { + return ModuleDescriptor.read(in).name(); + } + + /** + * Returns 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), + * or {@link JavaPathType#CLASSES} otherwise. A JAR file without module descriptor but with + * an "Automatic-Module-Name" manifest attribute is considered modular. + */ + public JavaPathType getPathType() { + return descriptors.isEmpty() ? JavaPathType.CLASSES : JavaPathType.MODULES; + } + + /** + * Returns whether module hierarchy was detected. If 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; + } + + /** + * Returns 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. + * + *

          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.

          + */ + @Nonnull + public Map getModuleNames() { + return descriptors; + } + + /** + * Returns whether the dependency contains a module of the given name. + */ + public boolean containsModule(final String name) { + return descriptors.containsValue(name); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java new file mode 100644 index 000000000000..d123205bb02e --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java @@ -0,0 +1,135 @@ +/* + * 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.internal.impl; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.PathType; + +/** + * Cache of {@link PathModularization} instances computed for given {@link Path} elements. + * The cache is used for avoiding the need to reopen the same files many times when the + * same dependency is used for different scope. For example a path used for compilation + * is typically also used for tests. + */ +final class PathModularizationCache { + /** + * Module information for each JAR file or output directories. + * Cached when first requested to avoid decoding the module descriptors multiple times. + * + * @see #getModuleInfo(Path) + */ + private final Map moduleInfo; + + /** + * Whether JAR files are modular. This map is redundant with {@link #moduleInfo}, + * but cheaper to compute when the module names are not needed. + * + * @see #getPathType(Path) + */ + private final Map pathTypes; + + /** + * Creates an initially empty cache. + */ + PathModularizationCache() { + moduleInfo = new HashMap<>(); + pathTypes = new HashMap<>(); + } + + /** + * Gets module information for the given JAR file or output directory. + * Module descriptors are read when first requested, then cached. + */ + PathModularization getModuleInfo(final Path path) throws IOException { + PathModularization info = moduleInfo.get(path); + if (info == null) { + info = new PathModularization(path, true); + moduleInfo.put(path, info); + pathTypes.put(path, info.getPathType()); + } + return info; + } + + /** + * Returns {@link JavaPathType#MODULES} if the given JAR file or output directory is modular. + * This is used in heuristic rules for deciding whether to place a dependency on the class-path + * or on the module-path when the {@code "jar"} artifact type is used. + */ + private PathType getPathType(final Path path) throws IOException { + PathType type = pathTypes.get(path); + if (type == null) { + type = new PathModularization(path, false).getPathType(); + pathTypes.put(path, type); + } + return type; + } + + /** + * Selects the type of path where to place the given dependency. + * This method returns one of the values specified in the given array. + * This method does not handle the patch-module paths, because the patches + * depend on which modules have been previously added on the module-paths. + * + *

          If the dependency can be a constituent of both the class-path and the module-path, + * then the path type is determined by checking if the dependency is modular.

          + * + * @param types types of path where a dependency can be placed + * @param filter filter the paths accepted by the tool which will consume the path + * @param path path to the JAR file or output directory of the dependency + * @return where to place the dependency, or an empty value if the placement cannot be determined + * @throws IOException if an error occurred while reading module information + */ + Optional selectPathType(final Set types, final Predicate filter, final Path path) + throws IOException { + PathType selected = null; + boolean classes = false; + boolean modules = false; + boolean unknown = false; + for (PathType type : types) { + if (filter.test(type)) { + if (JavaPathType.CLASSES.equals(type)) { + classes = true; + } else if (JavaPathType.MODULES.equals(type)) { + modules = true; + } else { + unknown = true; + } + if (selected == null) { + selected = type; + } else if (unknown) { + // More than one filtered value, and we don't know how to handle at least one of them. + // TODO: add a plugin mechanism for allowing plugin to specify their selection algorithm. + return Optional.empty(); + } + } + } + if (classes & modules) { + selected = getPathType(path); + } + return Optional.ofNullable(selected); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java index 801bfef782df..fd03cf821918 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java @@ -34,7 +34,7 @@ public class BomTypeProvider implements Provider { private final Type type; public BomTypeProvider() { - this.type = new DefaultType(NAME, Language.NONE, "pom", null, false, false); + this.type = new DefaultType(NAME, Language.NONE, "pom", null, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ClasspathJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ClasspathJarTypeProvider.java new file mode 100644 index 000000000000..e8836978249a --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ClasspathJarTypeProvider.java @@ -0,0 +1,51 @@ +/* + * 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.internal.impl.types; + +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.Language; +import org.apache.maven.api.Type; +import org.apache.maven.internal.impl.DefaultType; + +/** + * Type provider for a JAR file to unconditionally place on the class-path. + * Dependencies of this type are class-path constituents only. + * + * @see Type#CLASSPATH_JAR + */ +@Named(ClasspathJarTypeProvider.NAME) +@Singleton +public class ClasspathJarTypeProvider implements Provider { + public static final String NAME = Type.CLASSPATH_JAR; + + private final Type type; + + public ClasspathJarTypeProvider() { + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, false, JavaPathType.CLASSES); + } + + @Override + public Type get() { + return type; + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java index 5512b8e44224..d8c319b04b6a 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java @@ -34,7 +34,7 @@ public class EarTypeProvider implements Provider { private final Type type; public EarTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "ear", null, false, true); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "ear", null, true); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java index a1a97dfcbb1b..57e678cea91a 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java @@ -22,6 +22,7 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Language; import org.apache.maven.api.Type; import org.apache.maven.internal.impl.DefaultType; @@ -34,7 +35,7 @@ public class EjbClientTypeProvider implements Provider { private final Type type; public EjbClientTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "client", true, false); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "client", false, JavaPathType.CLASSES); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java index 01a8dfcb9fec..d58890bd76f3 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java @@ -22,6 +22,7 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Language; import org.apache.maven.api.Type; import org.apache.maven.internal.impl.DefaultType; @@ -34,7 +35,7 @@ public class EjbTypeProvider implements Provider { private final Type type; public EjbTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, true, false); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, false, JavaPathType.CLASSES); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java index df61f6bd3ba5..a0737f403fe6 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java @@ -22,19 +22,29 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Language; import org.apache.maven.api.Type; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for a JAR file that can be placed either on the class-path or on the module-path. + * Dependencies of this type are class-path constituents and module-path constituents. + * Only one of those constituents shall be effective for any given dependency. + * The choice may depend on heuristic rules. + * + * @see Type#JAR + */ @Named(JarTypeProvider.NAME) @Singleton public class JarTypeProvider implements Provider { - public static final String NAME = "jar"; + public static final String NAME = Type.JAR; private final Type type; public JarTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, true, false); + this.type = new DefaultType( + NAME, Language.JAVA_FAMILY, "jar", null, false, JavaPathType.CLASSES, JavaPathType.MODULES); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java index 4e90d4591a58..10dfee272183 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java @@ -26,15 +26,20 @@ import org.apache.maven.api.Type; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for source code packaged in a JAR file. + * + * @see Type#JAVA_SOURCE + */ @Named(JavaSourceTypeProvider.NAME) @Singleton public class JavaSourceTypeProvider implements Provider { - public static final String NAME = "java-source"; + public static final String NAME = Type.JAVA_SOURCE; private final Type type; public JavaSourceTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "sources", false, false); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "sources", false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java index 1f6e9aee8fa0..99f4fb179400 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java @@ -22,19 +22,25 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Language; import org.apache.maven.api.Type; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for javadoc packaged in a JAR file. + * + * @see Type#JAVADOC + */ @Named(JavadocTypeProvider.NAME) @Singleton public class JavadocTypeProvider implements Provider { - public static final String NAME = "javadoc"; + public static final String NAME = Type.JAVADOC; private final Type type; public JavadocTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "javadoc", true, false); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "javadoc", false, JavaPathType.CLASSES); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java index ec5a45ff55ba..bef3837cc3ef 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java @@ -22,19 +22,25 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Language; import org.apache.maven.api.Type; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for a Maven plugin. + * + * @see Type#MAVEN_PLUGIN + */ @Named(MavenPluginTypeProvider.NAME) @Singleton public class MavenPluginTypeProvider implements Provider { - public static final String NAME = "maven-plugin"; + public static final String NAME = Type.MAVEN_PLUGIN; private final Type type; public MavenPluginTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, true, false); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, false, JavaPathType.CLASSES); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ModularJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ModularJarTypeProvider.java new file mode 100644 index 000000000000..9dfa5a0df54a --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ModularJarTypeProvider.java @@ -0,0 +1,51 @@ +/* + * 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.internal.impl.types; + +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.apache.maven.api.JavaPathType; +import org.apache.maven.api.Language; +import org.apache.maven.api.Type; +import org.apache.maven.internal.impl.DefaultType; + +/** + * Type provider for a JAR file to unconditionally place on the module-path. + * Dependencies of this type are module-path constituents only. + * + * @see Type#MODULAR_JAR + */ +@Named(ModularJarTypeProvider.NAME) +@Singleton +public class ModularJarTypeProvider implements Provider { + public static final String NAME = Type.MODULAR_JAR; + + private final Type type; + + public ModularJarTypeProvider() { + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", null, false, JavaPathType.MODULES); + } + + @Override + public Type get() { + return type; + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java index b804b6959748..1f51178991a5 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java @@ -34,7 +34,7 @@ public class ParTypeProvider implements Provider { private final Type type; public ParTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "par", null, false, true); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "par", null, true); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java index 9f385641165a..7b52f299a2f9 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java @@ -26,15 +26,20 @@ import org.apache.maven.api.Type; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for a POM file. + * + * @see Type#POM + */ @Named(PomTypeProvider.NAME) @Singleton public class PomTypeProvider implements Provider { - public static final String NAME = "pom"; + public static final String NAME = Type.POM; private final Type type; public PomTypeProvider() { - this.type = new DefaultType(NAME, Language.NONE, "pom", null, false, false); + this.type = new DefaultType(NAME, Language.NONE, "pom", null, false); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java index 39e36777c0ba..3dd81a68bb4a 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java @@ -34,7 +34,7 @@ public class RarTypeProvider implements Provider { private final Type type; public RarTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "rar", null, false, true); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "rar", null, true); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java index 39f9653e9f99..00bb4c20fdfd 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java @@ -22,19 +22,28 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.maven.api.JavaPathType; import org.apache.maven.api.Language; import org.apache.maven.api.Type; import org.apache.maven.internal.impl.DefaultType; +/** + * Type provider for a JAR file containing test classes. Dependencies of this type are class-path constituents + * or {@code --patch-module} option values. For any dependency, the choice depends on whether the main JAR file + * was placed on the class-path or module-path respectively. + * + * @see Type#TEST_JAR + */ @Named(TestJarTypeProvider.NAME) @Singleton public class TestJarTypeProvider implements Provider { - public static final String NAME = "test-jar"; + public static final String NAME = Type.TEST_JAR; private final Type type; public TestJarTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "jar", "tests", true, false); + this.type = new DefaultType( + NAME, Language.JAVA_FAMILY, "jar", "tests", false, JavaPathType.CLASSES, JavaPathType.PATCH_MODULE); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java index 732ff09a7e10..cdde4a512833 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java @@ -34,7 +34,7 @@ public class WarTypeProvider implements Provider { private final Type type; public WarTypeProvider() { - this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "war", null, false, true); + this.type = new DefaultType(NAME, Language.JAVA_FAMILY, "war", null, true); } @Override diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java index 80ba4e7cdf2e..64087c262d47 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java +++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java @@ -36,30 +36,38 @@ class TransformedArtifactHandler implements ArtifactHandler { this.packaging = requireNonNull(packaging); } + @Override public String getClassifier() { return classifier; } + @Override public String getDirectory() { return null; } + @Override public String getExtension() { return extension; } + @Override public String getLanguage() { return "none"; } + @Override public String getPackaging() { return packaging; } + @Override + @Deprecated public boolean isAddedToClasspath() { return false; } + @Override public boolean isIncludesDependencies() { return false; } diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java index 0e165e04cb30..9b58e0212646 100644 --- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java +++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java @@ -32,12 +32,14 @@ import java.util.Objects; import java.util.Properties; import java.util.Set; +import java.util.function.Predicate; import org.apache.maven.RepositoryUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.artifact.DependencyResolutionRequiredException; import org.apache.maven.artifact.factory.ArtifactFactory; +import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.filter.ArtifactFilter; import org.apache.maven.lifecycle.internal.DefaultProjectArtifactFactory; @@ -320,68 +322,97 @@ public List getTestCompileSourceRoots() { return testCompileSourceRoots; } - public List getCompileClasspathElements() throws DependencyResolutionRequiredException { - List list = new ArrayList<>(getArtifacts().size() + 1); - - String d = getBuild().getOutputDirectory(); - if (d != null) { - list.add(d); - } - - for (Artifact a : getArtifacts()) { - if (a.getArtifactHandler().isAddedToClasspath()) { - // TODO let the scope handler deal with this - if (Artifact.SCOPE_COMPILE.equals(a.getScope()) - || Artifact.SCOPE_PROVIDED.equals(a.getScope()) - || Artifact.SCOPE_SYSTEM.equals(a.getScope())) { - addArtifactPath(a, list); - } - } - } + // TODO let the scope handler deal with this + private static boolean isCompilePathElement(final String scope) { + return Artifact.SCOPE_COMPILE.equals(scope) + || Artifact.SCOPE_PROVIDED.equals(scope) + || Artifact.SCOPE_SYSTEM.equals(scope); + } - return list; + // TODO let the scope handler deal with this + private static boolean isRuntimePathElement(final String scope) { + return Artifact.SCOPE_COMPILE.equals(scope) || Artifact.SCOPE_RUNTIME.equals(scope); } - // TODO this checking for file == null happens because the resolver has been confused about the root - // artifact or not. things like the stupid dummy artifact coming from surefire. - public List getTestClasspathElements() throws DependencyResolutionRequiredException { - List list = new ArrayList<>(getArtifacts().size() + 2); + // TODO let the scope handler deal with this + private static boolean isTestPathElement(final String scope) { + return true; + } - String d = getBuild().getTestOutputDirectory(); - if (d != null) { - list.add(d); + /** + * Returns a filtered list of classpath elements. This method is invoked when the caller + * requested that all dependencies are placed on the classpath, with no module-path element. + * + * @param scopeFilter a filter returning {@code true} for the artifact scopes to accept. + * @param includeTestDir whether to include the test directory in the classpath elements. + * @return paths of all artifacts placed on the classpath. + * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + */ + private List getClasspathElements(final Predicate scopeFilter, final boolean includeTestDir) + throws DependencyResolutionRequiredException { + final List list = new ArrayList<>(getArtifacts().size() + 2); + if (includeTestDir) { + String d = getBuild().getTestOutputDirectory(); + if (d != null) { + list.add(d); + } } - - d = getBuild().getOutputDirectory(); + String d = getBuild().getOutputDirectory(); if (d != null) { list.add(d); } - for (Artifact a : getArtifacts()) { - if (a.getArtifactHandler().isAddedToClasspath()) { - addArtifactPath(a, list); + final File f = a.getFile(); + if (f != null && scopeFilter.test(a.getScope())) { + final ArtifactHandler h = a.getArtifactHandler(); + if (h.isAddedToClasspath()) { + list.add(f.getPath()); + } } } - return list; } - public List getRuntimeClasspathElements() throws DependencyResolutionRequiredException { - List list = new ArrayList<>(getArtifacts().size() + 1); + /** + * Returns the elements placed on the classpath for compilation. + * This method can be invoked when the caller does not support module-path. + * + * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + * + * @deprecated This method is unreliable because it does not consider other dependency properties. + * See {@link org.apache.maven.api.JavaPathType} instead for better analysis. + */ + @Deprecated + public List getCompileClasspathElements() throws DependencyResolutionRequiredException { + return getClasspathElements(MavenProject::isCompilePathElement, false); + } - String d = getBuild().getOutputDirectory(); - if (d != null) { - list.add(d); - } + /** + * Returns the elements placed on the classpath for tests. + * This method can be invoked when the caller does not support module-path. + * + * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + * + * @deprecated This method is unreliable because it does not consider other dependency properties. + * See {@link org.apache.maven.api.JavaPathType} instead for better analysis. + */ + @Deprecated + public List getTestClasspathElements() throws DependencyResolutionRequiredException { + return getClasspathElements(MavenProject::isTestPathElement, true); + } - for (Artifact a : getArtifacts()) { - if (a.getArtifactHandler().isAddedToClasspath() - // TODO let the scope handler deal with this - && (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope()))) { - addArtifactPath(a, list); - } - } - return list; + /** + * Returns the elements placed on the classpath for runtime. + * This method can be invoked when the caller does not support module-path. + * + * @throws DependencyResolutionRequiredException if an artifact file is used, but has not been resolved + * + * @deprecated This method is unreliable because it does not consider other dependency properties. + * See {@link org.apache.maven.api.JavaPathType} instead for better analysis. + */ + @Deprecated + public List getRuntimeClasspathElements() throws DependencyResolutionRequiredException { + return getClasspathElements(MavenProject::isRuntimePathElement, false); } // ---------------------------------------------------------------------- @@ -1111,13 +1142,6 @@ private void deepCopy(MavenProject project) { lifecyclePhases.addAll(project.lifecyclePhases); } - private void addArtifactPath(Artifact artifact, List classpath) { - File file = artifact.getFile(); - if (file != null) { - classpath.add(file.getPath()); - } - } - private static String getProjectReferenceId(String groupId, String artifactId, String version) { StringBuilder buffer = new StringBuilder(128); buffer.append(groupId).append(':').append(artifactId).append(':').append(version); @@ -1347,9 +1371,7 @@ public List getCompileArtifacts() { // TODO classpath check doesn't belong here - that's the other method if (a.getArtifactHandler().isAddedToClasspath()) { // TODO let the scope handler deal with this - if (Artifact.SCOPE_COMPILE.equals(a.getScope()) - || Artifact.SCOPE_PROVIDED.equals(a.getScope()) - || Artifact.SCOPE_SYSTEM.equals(a.getScope())) { + if (isCompilePathElement(a.getScope())) { list.add(a); } } @@ -1369,9 +1391,7 @@ public List getCompileDependencies() { for (Artifact a : getArtifacts()) { // TODO let the scope handler deal with this - if (Artifact.SCOPE_COMPILE.equals(a.getScope()) - || Artifact.SCOPE_PROVIDED.equals(a.getScope()) - || Artifact.SCOPE_SYSTEM.equals(a.getScope())) { + if (isCompilePathElement(a.getScope())) { Dependency dependency = new Dependency(); dependency.setArtifactId(a.getArtifactId()); @@ -1437,7 +1457,7 @@ public List getRuntimeDependencies() { for (Artifact a : getArtifacts()) { // TODO let the scope handler deal with this - if (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope())) { + if (isRuntimePathElement(a.getScope())) { Dependency dependency = new Dependency(); dependency.setArtifactId(a.getArtifactId()); @@ -1459,9 +1479,7 @@ public List getRuntimeArtifacts() { for (Artifact a : getArtifacts()) { // TODO classpath check doesn't belong here - that's the other method - if (a.getArtifactHandler().isAddedToClasspath() - // TODO let the scope handler deal with this - && (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope()))) { + if (a.getArtifactHandler().isAddedToClasspath() && isRuntimePathElement(a.getScope())) { list.add(a); } } @@ -1481,7 +1499,10 @@ public List getSystemClasspathElements() throws DependencyResolutionRequ if (a.getArtifactHandler().isAddedToClasspath()) { // TODO let the scope handler deal with this if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) { - addArtifactPath(a, list); + File f = a.getFile(); + if (f != null) { + list.add(f.getPath()); + } } } } diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java index d5bb916664dc..18c3442d0635 100644 --- a/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java +++ b/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java @@ -57,30 +57,38 @@ public List getManagedDependencies() { // TODO: this is duplicate of MavenPluginArtifactHandlerProvider provided one static class PluginArtifactHandler implements ArtifactHandler { + @Override public String getClassifier() { return null; } + @Override public String getDirectory() { return null; } + @Override public String getExtension() { return "jar"; } + @Override public String getLanguage() { return "none"; } + @Override public String getPackaging() { return "maven-plugin"; } + @Override + @Deprecated public boolean isAddedToClasspath() { return true; } + @Override public boolean isIncludesDependencies() { return false; } diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java index 8d75eb76c576..c040fc93446e 100644 --- a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java +++ b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java @@ -62,30 +62,38 @@ public List getManagedDependencies() { // TODO: this is duplicate of PomArtifactHandlerProvider provided one static class PomArtifactHandler implements ArtifactHandler { + @Override public String getClassifier() { return null; } + @Override public String getDirectory() { return null; } + @Override public String getExtension() { return "pom"; } + @Override public String getLanguage() { return "none"; } + @Override public String getPackaging() { return "pom"; } + @Override + @Deprecated public boolean isAddedToClasspath() { return false; } + @Override public boolean isIncludesDependencies() { return false; } diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java index 18ce020307f5..26ee61bcf115 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java +++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java @@ -172,7 +172,7 @@ void testResolveArtifactCoordinateDependencies() { assertNotNull(paths); assertEquals(10, paths.size()); - assertTrue(paths.get(0).getFileName().toString().equals("test-extension-1.jar")); + assertEquals("test-extension-1.jar", paths.get(0).getFileName().toString()); } @Test diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java index cb86c6efdbc7..30ebee3972d8 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java +++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java @@ -39,30 +39,38 @@ public TestArtifactHandler(String type, String extension) { this.extension = extension; } + @Override public String getClassifier() { return null; } + @Override public String getDirectory() { return getPackaging() + "s"; } + @Override public String getExtension() { return extension; } + @Override public String getLanguage() { return "java"; } + @Override public String getPackaging() { return type; } + @Override + @Deprecated public boolean isAddedToClasspath() { return true; } + @Override public boolean isIncludesDependencies() { return false; } diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/FatArtifactTraverser.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/FatArtifactTraverser.java new file mode 100644 index 000000000000..903967197592 --- /dev/null +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/FatArtifactTraverser.java @@ -0,0 +1,54 @@ +/* + * 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.repository.internal; + +import java.util.Objects; + +import org.eclipse.aether.artifact.ArtifactProperties; +import org.eclipse.aether.collection.DependencyCollectionContext; +import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.graph.Dependency; + +public final class FatArtifactTraverser implements DependencyTraverser { + public FatArtifactTraverser() {} + + public boolean traverseDependency(Dependency dependency) { + Objects.requireNonNull(dependency, "dependency cannot be null"); + + String prop = dependency.getArtifact().getProperty(ArtifactProperties.INCLUDES_DEPENDENCIES, ""); + return !Boolean.parseBoolean(prop); + } + + public DependencyTraverser deriveChildTraverser(DependencyCollectionContext context) { + Objects.requireNonNull(context, "context cannot be null"); + return this; + } + + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else { + return null != obj && this.getClass().equals(obj.getClass()); + } + } + + public int hashCode() { + return this.getClass().hashCode(); + } +} diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java index a87b6cefdcdb..d9ffb72d3318 100644 --- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java +++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java @@ -39,7 +39,6 @@ import org.eclipse.aether.util.graph.transformer.ConflictResolver; import org.eclipse.aether.util.graph.transformer.NearestVersionSelector; import org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector; -import org.eclipse.aether.util.graph.traverser.FatArtifactTraverser; import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy; import static java.util.Objects.requireNonNull; From fe3975fa5a96ed53290eac0b475aeee44edaaf9a Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Thu, 1 Feb 2024 08:45:07 +0100 Subject: [PATCH 28/31] Fix javadoc --- .../internal/impl/DefaultDependencyResolverResult.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java index 2b2d6a8810bb..b41d307ab363 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java @@ -43,7 +43,7 @@ * *
            *
          • {@link #addOutputDirectory(Path, Path, PathModularizationCache)} (optional)
          • - *
          • {@link #addDependency(Node, Dependency, Set, Path, PathModularizationCache)}
          • + *
          • {@link #addDependency(Node, Dependency, Predicate, Path, PathModularizationCache)}
          • *
          * * @see DefaultDependencyResolver#resolve(DependencyResolverRequest) @@ -87,7 +87,7 @@ final class DefaultDependencyResolverResult implements DependencyResolverResult /** * Creates an initially empty result. Callers should add path elements by calls - * to {@link #addDependency(Node, Dependency, Path, PathModularizationCache)}. + * to {@link #addDependency(Node, Dependency, Predicate, Path, PathModularizationCache)}. * * @param exceptions the exceptions that occurred while building the dependency graph * @param root the root node of the dependency graph @@ -137,7 +137,7 @@ private void addPathElement(final PathType type, final Path path) { * *
        * - * This method must be invoked before {@link #addDependency(Node, Dependency, Path)} + * This method must be invoked before {@link #addDependency(Node, Dependency, Predicate, Path, PathModularizationCache)} * if output directories are desired on the class-path or module-path. * This method can be invoked at most once. * @@ -145,6 +145,8 @@ private void addPathElement(final PathType type, final Path path) { * @param test the test output directory, or {@code null} if none * @param cache cache of module information about each dependency * @throws IOException if an error occurred while reading module information + * + * TODO: this is currently not called */ void addOutputDirectory(final Path main, final Path test, final PathModularizationCache cache) throws IOException { if (outputModules != null) { From dd8738440bea64e28776ad8a67a4586ced06e226 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sun, 4 Feb 2024 18:41:50 +0100 Subject: [PATCH 29/31] Add Javadoc in `Session` interface and some `@Nonnull` annotations. Note: contains some "todo" about aspects that may need clarification. --- .../java/org/apache/maven/api/Session.java | 218 +++++++++++++++--- .../maven/internal/impl/AbstractSession.java | 22 +- 2 files changed, 206 insertions(+), 34 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index 4f414fe1fe0c..e6ecf4d25b45 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -195,13 +195,21 @@ public interface Session { /** * Shortcut for {@code getService(RepositoryFactory.class).createLocal(...)}. * + * @param path location of the local repository to create + * @return cache of artifacts downloaded from a remote repository or built locally + * * @see org.apache.maven.api.services.RepositoryFactory#createLocal(Path) */ - LocalRepository createLocalRepository(Path path); + @Nonnull + LocalRepository createLocalRepository(@Nonnull Path path); /** * Shortcut for {@code getService(RepositoryFactory.class).createRemote(...)}. * + * @param id identifier of the remote repository to create + * @param url location of the remote repository + * @return remote repository that can be used to download or upload artifacts + * * @see org.apache.maven.api.services.RepositoryFactory#createRemote(String, String) */ @Nonnull @@ -210,48 +218,76 @@ public interface Session { /** * Shortcut for {@code getService(RepositoryFactory.class).createRemote(...)}. * + * @param repository information needed for establishing connections with remote repository + * @return remote repository that can be used to download or upload artifacts + * * @see org.apache.maven.api.services.RepositoryFactory#createRemote(Repository) */ @Nonnull RemoteRepository createRemoteRepository(@Nonnull Repository repository); /** + * Creates a coordinate out of string that is formatted like: + * {@code :[:[:]]:}. + *

        * Shortcut for {@code getService(ArtifactFactory.class).create(...)}. * - * @see org.apache.maven.api.services.ArtifactCoordinateFactory#create(Session, String, String, String, String) + * @param coordString the string having "standard" coordinate. + * @return coordinate used to point to the artifact + * + * @see org.apache.maven.api.services.ArtifactCoordinateFactory#create(Session, String) */ - ArtifactCoordinate createArtifactCoordinate(String groupId, String artifactId, String version, String extension); + @Nonnull + ArtifactCoordinate createArtifactCoordinate(@Nonnull String coordString); /** - * Creates a coordinate out of string that is formatted like: - * {@code :[:[:]]:} - *

        * Shortcut for {@code getService(ArtifactFactory.class).create(...)}. * - * @param coordString the string having "standard" coordinate. - * @return an {@code ArtifactCoordinate}, never {@code null} - * @see org.apache.maven.api.services.ArtifactCoordinateFactory#create(Session, String) + * @param groupId the group identifier, or {@code null} is unspecified + * @param artifactId the artifact identifier, or {@code null} is unspecified + * @param version the artifact version, or {@code null} is unspecified + * @param extension the artifact extension, or {@code null} is unspecified + * @return coordinate used to point to the artifact + * + * @see org.apache.maven.api.services.ArtifactCoordinateFactory#create(Session, String, String, String, String) */ - ArtifactCoordinate createArtifactCoordinate(String coordString); + @Nonnull + ArtifactCoordinate createArtifactCoordinate(String groupId, String artifactId, String version, String extension); /** * Shortcut for {@code getService(ArtifactFactory.class).create(...)}. * + * @param groupId the group identifier, or {@code null} is unspecified + * @param artifactId the artifact identifier, or {@code null} is unspecified + * @param version the artifact version, or {@code null} is unspecified + * @param classifier the artifact classifier, or {@code null} is unspecified + * @param extension the artifact extension, or {@code null} is unspecified + * @param type the artifact type, or {@code null} is unspecified + * @return coordinate used to point to the artifact + * * @see org.apache.maven.api.services.ArtifactCoordinateFactory#create(Session, String, String, String, String, String, String) */ + @Nonnull ArtifactCoordinate createArtifactCoordinate( String groupId, String artifactId, String version, String classifier, String extension, String type); /** * Shortcut for {@code getService(ArtifactFactory.class).create(...)}. * + * @param artifact artifact from which to get coordinates + * @return coordinate used to point to the artifact + * * @see org.apache.maven.api.services.ArtifactCoordinateFactory#create(Session, String, String, String, String, String, String) */ - ArtifactCoordinate createArtifactCoordinate(Artifact artifact); + @Nonnull + ArtifactCoordinate createArtifactCoordinate(@Nonnull Artifact artifact); /** * Shortcut for {@code getService(DependencyFactory.class).create(...)}. * + * @param coordinate artifact coordinate to get as a dependency coordinate + * @return dependency coordinate for the given artifact + * * @see DependencyCoordinateFactory#create(Session, ArtifactCoordinate) */ @Nonnull @@ -260,6 +296,9 @@ ArtifactCoordinate createArtifactCoordinate( /** * Shortcut for {@code getService(DependencyFactory.class).create(...)}. * + * @param dependency dependency for which to get the coordinate + * @return coordinate for the given dependency + * * @see DependencyCoordinateFactory#create(Session, Dependency) */ @Nonnull @@ -268,85 +307,131 @@ ArtifactCoordinate createArtifactCoordinate( /** * Shortcut for {@code getService(ArtifactFactory.class).create(...)}. * + * @param groupId the group identifier, or {@code null} is unspecified + * @param artifactId the artifact identifier, or {@code null} is unspecified + * @param version the artifact version, or {@code null} is unspecified + * @param extension the artifact extension, or {@code null} is unspecified + * @return artifact with the given coordinates + * * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String) */ + @Nonnull Artifact createArtifact(String groupId, String artifactId, String version, String extension); /** * Shortcut for {@code getService(ArtifactFactory.class).create(...)}. * + * @param groupId the group identifier, or {@code null} is unspecified + * @param artifactId the artifact identifier, or {@code null} is unspecified + * @param version the artifact version, or {@code null} is unspecified + * @param classifier the artifact classifier, or {@code null} is unspecified + * @param extension the artifact extension, or {@code null} is unspecified + * @param type the artifact type, or {@code null} is unspecified + * @return artifact with the given coordinates + * * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String) */ + @Nonnull Artifact createArtifact( String groupId, String artifactId, String version, String classifier, String extension, String type); /** * Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}. * - * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) + * @param coordinate coordinates of the artifact to resolve + * @return requested artifact together with the path to its file * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed + * + * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) */ - Map.Entry resolveArtifact(ArtifactCoordinate coordinate); + @Nonnull + Map.Entry resolveArtifact(@Nonnull ArtifactCoordinate coordinate); /** * Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}. * - * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) + * @param coordinates coordinates of all artifacts to resolve + * @return requested artifacts together with the paths to their files * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed + * + * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) */ - Map resolveArtifacts(ArtifactCoordinate... coordinates); + @Nonnull + Map resolveArtifacts(@Nonnull ArtifactCoordinate... coordinates); /** * Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}. * - * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) + * @param coordinates coordinates of all artifacts to resolve + * @return requested artifacts together with the paths to their files * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed + * + * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) */ - Map resolveArtifacts(Collection coordinates); + @Nonnull + Map resolveArtifacts(@Nonnull Collection coordinates); /** * Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}. * - * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) + * @param artifact the artifact to resolve + * @return requested artifact together with the path to its file * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed + * + * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) */ - Map.Entry resolveArtifact(Artifact artifact); + @Nonnull + Map.Entry resolveArtifact(@Nonnull Artifact artifact); /** * Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}. * - * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) + * @param artifacts all artifacts to resolve + * @return requested artifacts together with the paths to their files * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed + * + * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection) */ - Map resolveArtifacts(Artifact... artifacts); + @Nonnull + Map resolveArtifacts(@Nonnull Artifact... artifacts); /** * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}. * - * @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection) + * @param artifacts the artifacts to install * @throws org.apache.maven.api.services.ArtifactInstallerException if the artifacts installation failed + * + * @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection) */ - void installArtifacts(Artifact... artifacts); + void installArtifacts(@Nonnull Artifact... artifacts); /** * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}. * - * @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection) + * @param artifacts the artifacts to install * @throws org.apache.maven.api.services.ArtifactInstallerException if the artifacts installation failed + * + * @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection) */ - void installArtifacts(Collection artifacts); + void installArtifacts(@Nonnull Collection artifacts); /** * Shortcut for {@code getService(ArtifactDeployer.class).deploy(...)}. * - * @see org.apache.maven.api.services.ArtifactDeployer#deploy(Session, RemoteRepository, Collection) + * @param repository the repository where to deploy artifacts + * @param artifacts the artifacts to deploy * @throws org.apache.maven.api.services.ArtifactDeployerException if the artifacts deployment failed + * + * @see org.apache.maven.api.services.ArtifactDeployer#deploy(Session, RemoteRepository, Collection) */ - void deployArtifact(RemoteRepository repository, Artifact... artifacts); + void deployArtifact(@Nonnull RemoteRepository repository, @Nonnull Artifact... artifacts); /** * Shortcut for {@code getService(ArtifactManager.class).setPath(...)}. * + * @param artifact the artifact for which to associate a path + * @param path path to associate to the given artifact + * * @see org.apache.maven.api.services.ArtifactManager#setPath(Artifact, Path) */ void setArtifactPath(@Nonnull Artifact artifact, @Nonnull Path path); @@ -354,6 +439,9 @@ Artifact createArtifact( /** * Shortcut for {@code getService(ArtifactManager.class).getPath(...)}. * + * @param artifact the artifact for which to get a path + * @return path associated to the given artifact + * * @see org.apache.maven.api.services.ArtifactManager#getPath(Artifact) */ @Nonnull @@ -365,6 +453,9 @@ Artifact createArtifact( *

        * Shortcut for {@code getService(LocalArtifactManager.class).getPathForLocalArtitact(...)}. * + * @param artifact the artifact for which to get a local path + * @return local path associated to the given artifact, or {@code null} if none + * * @see org.apache.maven.api.services.LocalRepositoryManager#getPathForLocalArtifact(Session, LocalRepository, Artifact) */ Path getPathForLocalArtifact(@Nonnull Artifact artifact); @@ -376,6 +467,10 @@ Artifact createArtifact( *

        * Shortcut for {@code getService(LocalArtifactManager.class).getPathForRemoteArtifact(...)}. * + * @param remote the repository from where artifacts are downloaded + * @param artifact the artifact for which to get a path + * @return path associated to the given artifact + * * @see org.apache.maven.api.services.LocalRepositoryManager#getPathForRemoteArtifact(Session, LocalRepository, RemoteRepository, Artifact) */ @Nonnull @@ -389,6 +484,9 @@ Artifact createArtifact( * In case there is {@link Artifact} in scope, the recommended way to perform this check is * use of {@link Artifact#isSnapshot()} instead. * + * @param version artifact version + * @return whether the given version is a snapshot + * * @see org.apache.maven.api.services.VersionParser#isSnapshot(String) */ boolean isVersionSnapshot(@Nonnull String version); @@ -396,6 +494,9 @@ Artifact createArtifact( /** * Shortcut for {@code getService(DependencyCollector.class).collect(...)} * + * @param artifact artifact for which to get the dependencies, including transitive ones + * @return root node of the dependency graph for the given artifact + * * @see org.apache.maven.api.services.DependencyCollector#collect(Session, Artifact) * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed */ @@ -405,6 +506,9 @@ Artifact createArtifact( /** * Shortcut for {@code getService(DependencyCollector.class).collect(...)} * + * @param project project for which to get the dependencies, including transitive ones + * @return root node of the dependency graph for the given project + * * @see org.apache.maven.api.services.DependencyCollector#collect(Session, Project) * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed */ @@ -418,6 +522,9 @@ Artifact createArtifact( *

        * Shortcut for {@code getService(DependencyCollector.class).resolve(...)} * + * @param dependency dependency for which to get transitive dependencies + * @return root node of the dependency graph for the given artifact + * * @see org.apache.maven.api.services.DependencyCollector#collect(Session, DependencyCoordinate) * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed */ @@ -427,18 +534,53 @@ Artifact createArtifact( /** * Shortcut for {@code getService(DependencyResolver.class).flatten(...)}. * - * @see org.apache.maven.api.services.DependencyResolver#flatten(Session, Node, PathScope) + * @param node node for which to get a flattened list + * @param scope build path scope (main compile, test compile, etc.) of desired nodes + * @return flattened list of node with the given build path scope * @throws org.apache.maven.api.services.DependencyResolverException if the dependency flattening failed + * + * @see org.apache.maven.api.services.DependencyResolver#flatten(Session, Node, PathScope) + * + * @todo Does the returned list include the given node? */ @Nonnull List flattenDependencies(@Nonnull Node node, @Nonnull PathScope scope); + /** + * Shortcut for {@code getService(DependencyResolver.class).resolve(...).getPaths()}. + * + * @param dependencyCoordinate coordinate of the dependency for which to get the paths + * @return paths to the transitive dependencies of the given dependency + * + * @see org.apache.maven.api.services.DependencyResolver#resolve(Session, DependencyCoordinate) + * + * @todo Does the returned list include the path to the given dependency? + */ @Nonnull List resolveDependencies(@Nonnull DependencyCoordinate dependencyCoordinate); + /** + * Shortcut for {@code getService(DependencyResolver.class).resolve(...).getPaths()}. + * + * @param dependencyCoordinates coordinates of all dependency for which to get the paths + * @return paths to the transitive dependencies of the given dependencies + * + * @see org.apache.maven.api.services.DependencyResolver#resolve(Session, List) + * + * @todo Does the returned list include the path to the given dependencies? + */ @Nonnull List resolveDependencies(@Nonnull List dependencyCoordinates); + /** + * Shortcut for {@code getService(DependencyResolver.class).resolve(...).getPaths()}. + * + * @param project the project for which to get dependencies + * @param scope build path scope (main compile, test compile, etc.) of desired paths + * @return paths to the transitive dependencies of the given project + * + * @see org.apache.maven.api.services.DependencyResolver#resolve(Session, Project, PathScope) + */ @Nonnull List resolveDependencies(@Nonnull Project project, @Nonnull PathScope scope); @@ -448,8 +590,11 @@ Artifact createArtifact( *

        * Shortcut for {@code getService(VersionResolver.class).resolve(...)} * - * @see org.apache.maven.api.services.VersionResolver#resolve(Session, ArtifactCoordinate) (String) + * @param artifact the artifact for which to resolve the version + * @return resolved version of the given artifact * @throws org.apache.maven.api.services.VersionResolverException if the resolution failed + * + * @see org.apache.maven.api.services.VersionResolver#resolve(Session, ArtifactCoordinate) (String) */ @Nonnull Version resolveVersion(@Nonnull ArtifactCoordinate artifact); @@ -462,9 +607,10 @@ Artifact createArtifact( * In this case though, the result contains simply the (parsed) input version, regardless of the * repositories and their contents. * + * @param artifact the artifact for which to resolve the versions * @return a list of resolved {@code Version}s. - * @see org.apache.maven.api.services.VersionRangeResolver#resolve(Session, ArtifactCoordinate) (String) * @throws org.apache.maven.api.services.VersionRangeResolverException if the resolution failed + * @see org.apache.maven.api.services.VersionRangeResolver#resolve(Session, ArtifactCoordinate) (String) */ @Nonnull List resolveVersionRange(@Nonnull ArtifactCoordinate artifact); @@ -474,8 +620,10 @@ Artifact createArtifact( *

        * Shortcut for {@code getService(VersionParser.class).parseVersion(...)}. * - * @see org.apache.maven.api.services.VersionParser#parseVersion(String) + * @param version the version string to parse + * @return the version parsed from the given string * @throws org.apache.maven.api.services.VersionParserException if the parsing failed + * @see org.apache.maven.api.services.VersionParser#parseVersion(String) */ @Nonnull Version parseVersion(@Nonnull String version); @@ -485,8 +633,10 @@ Artifact createArtifact( *

        * Shortcut for {@code getService(VersionParser.class).parseVersionRange(...)}. * - * @see org.apache.maven.api.services.VersionParser#parseVersionRange(String) + * @param versionRange the version string to parse + * @return the version range parsed from the given string * @throws org.apache.maven.api.services.VersionParserException if the parsing failed + * @see org.apache.maven.api.services.VersionParser#parseVersionRange(String) */ @Nonnull VersionRange parseVersionRange(@Nonnull String versionRange); @@ -496,8 +646,10 @@ Artifact createArtifact( *

        * Shortcut for {@code getService(VersionParser.class).parseVersionConstraint(...)}. * - * @see org.apache.maven.api.services.VersionParser#parseVersionConstraint(String) + * @param versionConstraint the version string to parse + * @return the version constraint parsed from the given string * @throws org.apache.maven.api.services.VersionParserException if the parsing failed + * @see org.apache.maven.api.services.VersionParser#parseVersionConstraint(String) */ @Nonnull VersionConstraint parseVersionConstraint(@Nonnull String versionConstraint); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index 1b9779011986..a79ceb5bf2ed 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -29,6 +29,7 @@ import java.util.Optional; import java.util.WeakHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; import org.apache.maven.api.*; import org.apache.maven.api.annotations.Nonnull; @@ -53,40 +54,49 @@ public abstract class AbstractSession implements InternalSession { private final Map allDependencies = Collections.synchronizedMap(new WeakHashMap<>()); + @Override public RemoteRepository getRemoteRepository(org.eclipse.aether.repository.RemoteRepository repository) { return allRepositories.computeIfAbsent(repository, DefaultRemoteRepository::new); } + @Override public Node getNode(org.eclipse.aether.graph.DependencyNode node) { return getNode(node, false); } + @Override public Node getNode(org.eclipse.aether.graph.DependencyNode node, boolean verbose) { return allNodes.computeIfAbsent(node, n -> new DefaultNode(this, n, verbose)); } @Nonnull + @Override public Artifact getArtifact(@Nonnull org.eclipse.aether.artifact.Artifact artifact) { return allArtifacts.computeIfAbsent(artifact, a -> new DefaultArtifact(this, a)); } @Nonnull + @Override public Dependency getDependency(@Nonnull org.eclipse.aether.graph.Dependency dependency) { return allDependencies.computeIfAbsent(dependency, d -> new DefaultDependency(this, d)); } + @Override public List getProjects(List projects) { return projects == null ? null : map(projects, this::getProject); } + @Override public Project getProject(MavenProject project) { return allProjects.computeIfAbsent(project.getId(), id -> new DefaultProject(this, project)); } + @Override public List toRepositories(List repositories) { return repositories == null ? null : map(repositories, this::toRepository); } + @Override public org.eclipse.aether.repository.RemoteRepository toRepository(RemoteRepository repository) { if (repository instanceof DefaultRemoteRepository) { return ((DefaultRemoteRepository) repository).getRepository(); @@ -96,6 +106,7 @@ public org.eclipse.aether.repository.RemoteRepository toRepository(RemoteReposit } } + @Override public org.eclipse.aether.repository.LocalRepository toRepository(LocalRepository repository) { if (repository instanceof DefaultLocalRepository) { return ((DefaultLocalRepository) repository).getRepository(); @@ -105,22 +116,28 @@ public org.eclipse.aether.repository.LocalRepository toRepository(LocalRepositor } } + @Override public List toArtifactRepositories(List repositories) { return repositories == null ? null : map(repositories, this::toArtifactRepository); } + @Override public abstract ArtifactRepository toArtifactRepository(RemoteRepository repository); + @Override public List toDependencies(Collection dependencies) { return dependencies == null ? null : map(dependencies, this::toDependency); } + @Override public abstract org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinate dependency); + @Override public List toArtifacts(Collection artifacts) { return artifacts == null ? null : map(artifacts, this::toArtifact); } + @Override public org.eclipse.aether.artifact.Artifact toArtifact(Artifact artifact) { File file = getService(ArtifactManager.class) .getPath(artifact) @@ -142,6 +159,7 @@ public org.eclipse.aether.artifact.Artifact toArtifact(Artifact artifact) { file); } + @Override public org.eclipse.aether.artifact.Artifact toArtifact(ArtifactCoordinate coord) { if (coord instanceof DefaultArtifactCoordinate) { return ((DefaultArtifactCoordinate) coord).getCoordinate(); @@ -335,7 +353,8 @@ public Map.Entry resolveArtifact(Artifact artifact) { @Override public Map resolveArtifacts(Artifact... artifacts) { ArtifactCoordinateFactory acf = getService(ArtifactCoordinateFactory.class); - List coords = map(Arrays.asList(artifacts), a -> acf.create(this, a)); + List coords = + Arrays.stream(artifacts).map(a -> acf.create(this, a)).collect(Collectors.toList()); return resolveArtifacts(coords); } @@ -420,6 +439,7 @@ public DependencyCoordinate createDependencyCoordinate(@Nonnull ArtifactCoordina * @see DependencyCoordinateFactory#create(Session, ArtifactCoordinate) */ @Nonnull + @Override public DependencyCoordinate createDependencyCoordinate(@Nonnull Dependency dependency) { return getService(DependencyCoordinateFactory.class).create(this, dependency); } From cb2386c47f353cb042725f7ae87d8b2fe5f6a71d Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sun, 4 Feb 2024 22:09:27 +0100 Subject: [PATCH 30/31] Add `Session.resolveDependencies(..., Collection) convenience method and expand an existing test case. --- .../java/org/apache/maven/api/Session.java | 30 ++++++++++ .../services/DependencyResolverRequest.java | 21 +++++++ .../maven/internal/impl/AbstractSession.java | 28 +++++++++ .../apache/maven/internal/impl/TestApi.java | 59 +++++++++++++------ 4 files changed, 119 insertions(+), 19 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index e6ecf4d25b45..cee4b74c9bca 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -584,6 +584,36 @@ Artifact createArtifact( @Nonnull List resolveDependencies(@Nonnull Project project, @Nonnull PathScope scope); + /** + * Shortcut for {@code getService(DependencyResolver.class).resolve(...).getDispatchedPaths()}. + * + * @param dependencyCoordinate coordinate of the dependency for which to get the paths + * @param scope build path scope (main compile, test compile, etc.) of desired paths + * @param desiredTypes the type of paths to include in the result + * @return paths to the transitive dependencies of the given project + * + * @see org.apache.maven.api.services.DependencyResolver#resolve(Session, Project, PathScope) + */ + @Nonnull + Map> resolveDependencies( + @Nonnull DependencyCoordinate dependencyCoordinate, + @Nonnull PathScope scope, + @Nonnull Collection desiredTypes); + + /** + * Shortcut for {@code getService(DependencyResolver.class).resolve(...).getDispatchedPaths()}. + * + * @param project the project for which to get dependencies + * @param scope build path scope (main compile, test compile, etc.) of desired paths + * @param desiredTypes the type of paths to include in the result + * @return paths to the transitive dependencies of the given project + * + * @see org.apache.maven.api.services.DependencyResolver#resolve(Session, Project, PathScope) + */ + @Nonnull + Map> resolveDependencies( + @Nonnull Project project, @Nonnull PathScope scope, @Nonnull Collection desiredTypes); + /** * Resolves an artifact's meta version (if any) to a concrete version. For example, resolves "1.0-SNAPSHOT" * to "1.0-20090208.132618-23" or "RELEASE"/"LATEST" to "2.0". diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java index c0aa94ee194a..2f410a8a303f 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java @@ -173,12 +173,33 @@ public DependencyResolverRequestBuilder pathScope(@Nonnull PathScope pathScope) return this; } + /** + * Filters the types of paths to include in the result. + * The result will contain only the paths of types for which the predicate returned {@code true}. + * It is recommended to apply a filter for retaining only the types of paths of interest, + * because it can resolve ambiguities when a path could be of many types. + * + * @param pathTypeFilter predicate evaluating whether a path type should be included in the result + * @return {@code this} for method call chaining + */ @Nonnull public DependencyResolverRequestBuilder pathTypeFilter(@Nonnull Predicate pathTypeFilter) { this.pathTypeFilter = pathTypeFilter; return this; } + /** + * Specifies the type of paths to include in the result. This is a convenience method for + * {@link #pathTypeFilter(Predicate)} using {@link Collection#contains(Object)} as the filter. + * + * @param desiredTypes the type of paths to include in the result + * @return {@code this} for method call chaining + */ + @Nonnull + public DependencyResolverRequestBuilder pathTypeFilter(@Nonnull Collection desiredTypes) { + return pathTypeFilter(desiredTypes::contains); + } + @Override public DependencyResolverRequest build() { return new DefaultDependencyResolverRequest( diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index a79ceb5bf2ed..bc65ac91d881 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -503,6 +503,34 @@ public List resolveDependencies(Project project, PathScope scope) { .getPaths(); } + @Override + public Map> resolveDependencies( + @Nonnull DependencyCoordinate dependency, + @Nonnull PathScope scope, + @Nonnull Collection desiredTypes) { + return getService(DependencyResolver.class) + .resolve(DependencyResolverRequest.builder() + .session(this) + .dependency(dependency) + .pathScope(scope) + .pathTypeFilter(desiredTypes) + .build()) + .getDispatchedPaths(); + } + + @Override + public Map> resolveDependencies( + @Nonnull Project project, @Nonnull PathScope scope, @Nonnull Collection desiredTypes) { + return getService(DependencyResolver.class) + .resolve(DependencyResolverRequest.builder() + .session(this) + .project(project) + .pathScope(scope) + .pathTypeFilter(desiredTypes) + .build()) + .getDispatchedPaths(); + } + @Override public Path getPathForLocalArtifact(@Nonnull Artifact artifact) { return getService(LocalRepositoryManager.class).getPathForLocalArtifact(this, getLocalRepository(), artifact); diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java index 26ee61bcf115..ef654feca23b 100644 --- a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java +++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java @@ -23,6 +23,7 @@ import java.io.File; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -58,6 +59,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @PlexusTest @@ -126,6 +128,17 @@ void setup() { sessionScope.seed(InternalSession.class, InternalSession.from(this.session)); } + private Project project(Artifact artifact) { + return session.getService(ProjectBuilder.class) + .build(ProjectBuilderRequest.builder() + .session(session) + .path(session.getPathForLocalArtifact(artifact)) + .processPlugins(false) + .build()) + .getProject() + .get(); + } + @Test void testCreateAndResolveArtifact() { ArtifactCoordinate coord = @@ -144,14 +157,7 @@ void testCreateAndResolveArtifact() { void testBuildProject() { Artifact artifact = session.createArtifact("org.codehaus.plexus", "plexus-utils", "1.4.5", "pom"); - Project project = session.getService(ProjectBuilder.class) - .build(ProjectBuilderRequest.builder() - .session(session) - .path(session.getPathForLocalArtifact(artifact)) - .processPlugins(false) - .build()) - .getProject() - .get(); + Project project = project(artifact); assertNotNull(project); } @@ -165,28 +171,43 @@ void testCollectArtifactDependencies() { @Test void testResolveArtifactCoordinateDependencies() { - ArtifactCoordinate coord = - session.createArtifactCoordinate("org.apache.maven.core.test", "test-extension", "1", "jar"); + DependencyCoordinate coord = session.createDependencyCoordinate( + session.createArtifactCoordinate("org.apache.maven.core.test", "test-extension", "1", "jar")); - List paths = session.resolveDependencies(session.createDependencyCoordinate(coord)); + List paths = session.resolveDependencies(coord); assertNotNull(paths); assertEquals(10, paths.size()); assertEquals("test-extension-1.jar", paths.get(0).getFileName().toString()); + + // JUnit has an "Automatic-Module-Name", so it appears on the module path. + Map> dispatched = session.resolveDependencies( + coord, PathScope.TEST_COMPILE, Arrays.asList(JavaPathType.CLASSES, JavaPathType.MODULES)); + List classes = dispatched.get(JavaPathType.CLASSES); + List modules = dispatched.get(JavaPathType.MODULES); + assertEquals(2, dispatched.size()); + assertEquals(8, classes.size()); // "pluxus.pom" and "junit.jar" are excluded. + assertEquals(1, modules.size()); + assertEquals("test-extension-1.jar", classes.get(0).getFileName().toString()); + assertEquals("junit-4.13.1.jar", modules.get(0).getFileName().toString()); + assertTrue(paths.containsAll(classes)); + assertTrue(paths.containsAll(modules)); + + // If caller wants only a classpath, JUnit shall move there. + dispatched = session.resolveDependencies(coord, PathScope.TEST_COMPILE, Arrays.asList(JavaPathType.CLASSES)); + classes = dispatched.get(JavaPathType.CLASSES); + modules = dispatched.get(JavaPathType.MODULES); + assertEquals(1, dispatched.size()); + assertEquals(9, classes.size()); + assertNull(modules); + assertTrue(paths.containsAll(classes)); } @Test void testProjectDependencies() { Artifact pom = session.createArtifact("org.codehaus.plexus", "plexus-container-default", "1.0-alpha-32", "pom"); - Project project = session.getService(ProjectBuilder.class) - .build(ProjectBuilderRequest.builder() - .session(session) - .path(session.getPathForLocalArtifact(pom)) - .processPlugins(false) - .build()) - .getProject() - .get(); + Project project = project(pom); assertNotNull(project); Artifact artifact = session.createArtifact("org.apache.maven.core.test", "test-extension", "1", "jar"); From b72d1ce1327a1b2081028d53d03573d6c8a78290 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Sun, 4 Feb 2024 22:16:02 +0100 Subject: [PATCH 31/31] Remove @todo tags not recognized by Javadoc. However, those question still need to be answered. --- .../src/main/java/org/apache/maven/api/Session.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index cee4b74c9bca..56731f9f3a99 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -540,8 +540,6 @@ Artifact createArtifact( * @throws org.apache.maven.api.services.DependencyResolverException if the dependency flattening failed * * @see org.apache.maven.api.services.DependencyResolver#flatten(Session, Node, PathScope) - * - * @todo Does the returned list include the given node? */ @Nonnull List flattenDependencies(@Nonnull Node node, @Nonnull PathScope scope); @@ -553,8 +551,6 @@ Artifact createArtifact( * @return paths to the transitive dependencies of the given dependency * * @see org.apache.maven.api.services.DependencyResolver#resolve(Session, DependencyCoordinate) - * - * @todo Does the returned list include the path to the given dependency? */ @Nonnull List resolveDependencies(@Nonnull DependencyCoordinate dependencyCoordinate); @@ -566,8 +562,6 @@ Artifact createArtifact( * @return paths to the transitive dependencies of the given dependencies * * @see org.apache.maven.api.services.DependencyResolver#resolve(Session, List) - * - * @todo Does the returned list include the path to the given dependencies? */ @Nonnull List resolveDependencies(@Nonnull List dependencyCoordinates);