mirror of https://github.com/apache/maven.git
[MNG-8015] Control the type of path where each dependency can be placed (#1401)
Co-authored-by: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
This commit is contained in:
parent
a27873629f
commit
9780ca1baf
|
@ -22,6 +22,8 @@ import org.apache.maven.api.annotations.Experimental;
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>Path types are often exclusive. For example, a dependency should not be both on the Java class-path
|
||||
* and on the Java module-path.</p>
|
||||
*
|
||||
* @see org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths()
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Experimental
|
||||
public enum JavaPathType implements PathType {
|
||||
/**
|
||||
* The path identified by the Java {@code --class-path} option.
|
||||
* Used for compilation, execution and Javadoc among others.
|
||||
*
|
||||
* <p><b>Context-sensitive interpretation:</b>
|
||||
* 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:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>If {@link #MODULES} path type is also set, then the dependency can be placed either on the
|
||||
* class-path or on the module-path, but only one of those. The choice is up to the plugin,
|
||||
* possibly using heuristic rules (Maven 3 behavior).</li>
|
||||
* <li>If a {@link #patchModule(String)} is also set and the main JAR file 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.</li>
|
||||
* </ul>
|
||||
*/
|
||||
CLASSES("--class-path"),
|
||||
|
||||
/**
|
||||
* The path identified by the Java {@code --module-path} option.
|
||||
* Used for compilation, execution and Javadoc among others.
|
||||
*
|
||||
* <p><b>Context-sensitive interpretation:</b>
|
||||
* 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:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>If {@link #CLASSES} path type is also set, then the dependency <em>should</em> 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.</li>
|
||||
* <li>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.</li>
|
||||
* </ul>
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <p><b>Context-sensitive interpretation:</b>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* @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<String> 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(Iterable<? extends Path> paths) {
|
||||
return format(null, paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation shared with {@link Modular}.
|
||||
*/
|
||||
String format(String moduleName, Iterable<? extends Path> 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<String> 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<? extends Path> 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() + "]";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* 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 {
|
||||
/**
|
||||
* The type for all paths that could not be placed in any of the types requested by a caller.
|
||||
* This type can appear in the return value of a call to
|
||||
* {@link Session#resolveDependencies resolveDependencies(...)} when at least one dependency
|
||||
* cannot be associated to any type specified in the {@code desiredTypes} argument.
|
||||
* Plugins can choose to report a warning to users when unresolved paths exist.
|
||||
*/
|
||||
PathType UNRESOLVED = new PathType() {
|
||||
@Override
|
||||
public String name() {
|
||||
return "UNRESOLVED";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return "UNRESOLVED";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> option() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String option(Iterable<? extends Path> paths) {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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<String> 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.
|
||||
*
|
||||
* <p><b>Examples:</b>
|
||||
* If {@code paths} is a list containing two elements, {@code path1} and {@code path2}, then:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>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.</li>
|
||||
* <li>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.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @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<? extends Path> 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();
|
||||
}
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
|
||||
*
|
||||
* @see org.apache.maven.api.services.ArtifactCoordinateFactory#create(Session, String, String, String, String)
|
||||
*/
|
||||
ArtifactCoordinate createArtifactCoordinate(String groupId, String artifactId, String version, String extension);
|
||||
|
||||
/**
|
||||
* Creates a coordinate out of string that is formatted like:
|
||||
* {@code <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>}
|
||||
* {@code <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>}.
|
||||
* <p>
|
||||
* Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
|
||||
*
|
||||
* @param coordString the string having "standard" coordinate.
|
||||
* @return an {@code ArtifactCoordinate}, never {@code null}
|
||||
* @return coordinate used to point to the artifact
|
||||
*
|
||||
* @see org.apache.maven.api.services.ArtifactCoordinateFactory#create(Session, String)
|
||||
*/
|
||||
ArtifactCoordinate createArtifactCoordinate(String coordString);
|
||||
@Nonnull
|
||||
ArtifactCoordinate createArtifactCoordinate(@Nonnull String coordString);
|
||||
|
||||
/**
|
||||
* 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 coordinate used to point to the artifact
|
||||
*
|
||||
* @see org.apache.maven.api.services.ArtifactCoordinateFactory#create(Session, String, String, String, String)
|
||||
*/
|
||||
@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 @@ public interface Session {
|
|||
/**
|
||||
* 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 @@ public interface Session {
|
|||
/**
|
||||
* 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<Artifact, Path> resolveArtifact(ArtifactCoordinate coordinate);
|
||||
@Nonnull
|
||||
Map.Entry<Artifact, Path> 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<Artifact, Path> resolveArtifacts(ArtifactCoordinate... coordinates);
|
||||
@Nonnull
|
||||
Map<Artifact, Path> 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<Artifact, Path> resolveArtifacts(Collection<? extends ArtifactCoordinate> coordinates);
|
||||
@Nonnull
|
||||
Map<Artifact, Path> resolveArtifacts(@Nonnull Collection<? extends ArtifactCoordinate> 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<Artifact, Path> resolveArtifact(Artifact artifact);
|
||||
@Nonnull
|
||||
Map.Entry<Artifact, Path> 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<Artifact, Path> resolveArtifacts(Artifact... artifacts);
|
||||
@Nonnull
|
||||
Map<Artifact, Path> 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<Artifact> artifacts);
|
||||
void installArtifacts(@Nonnull Collection<Artifact> 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 @@ public interface Session {
|
|||
/**
|
||||
* 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 @@ public interface Session {
|
|||
* <p>
|
||||
* 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 @@ public interface Session {
|
|||
* <p>
|
||||
* 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 @@ public interface Session {
|
|||
* 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 @@ public interface Session {
|
|||
/**
|
||||
* 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 @@ public interface Session {
|
|||
/**
|
||||
* 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 @@ public interface Session {
|
|||
* <p>
|
||||
* 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,29 +534,91 @@ public interface Session {
|
|||
/**
|
||||
* 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)
|
||||
*/
|
||||
@Nonnull
|
||||
List<Node> 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)
|
||||
*/
|
||||
@Nonnull
|
||||
List<Path> 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)
|
||||
*/
|
||||
@Nonnull
|
||||
List<Path> resolveDependencies(@Nonnull List<DependencyCoordinate> 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<Path> 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<PathType, List<Path>> resolveDependencies(
|
||||
@Nonnull DependencyCoordinate dependencyCoordinate,
|
||||
@Nonnull PathScope scope,
|
||||
@Nonnull Collection<PathType> 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<PathType, List<Path>> resolveDependencies(
|
||||
@Nonnull Project project, @Nonnull PathScope scope, @Nonnull Collection<PathType> 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".
|
||||
* <p>
|
||||
* 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 +631,10 @@ public interface Session {
|
|||
* 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<Version> resolveVersionRange(@Nonnull ArtifactCoordinate artifact);
|
||||
|
@ -474,8 +644,10 @@ public interface Session {
|
|||
* <p>
|
||||
* 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 +657,10 @@ public interface Session {
|
|||
* <p>
|
||||
* 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 +670,10 @@ public interface Session {
|
|||
* <p>
|
||||
* 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);
|
||||
|
|
|
@ -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 @@ import org.apache.maven.api.model.Dependency;
|
|||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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,60 @@ import org.apache.maven.api.model.Dependency;
|
|||
@Experimental
|
||||
@Immutable
|
||||
public interface Type extends ExtensibleEnum {
|
||||
/**
|
||||
* Artifact type name for a POM file.
|
||||
*/
|
||||
String POM = "pom";
|
||||
|
||||
/**
|
||||
* Artifact type name for a BOM file.
|
||||
*/
|
||||
String BOM = "bom";
|
||||
|
||||
/**
|
||||
* 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 <i>dependency type</i>.
|
||||
|
@ -76,13 +132,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 +140,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.
|
||||
*
|
||||
* <p>It is nevertheless common to specify two or more types of path. For example,
|
||||
* a Java library may be compatible with either the class-path or the module-path,
|
||||
* and the user may have provided no instruction about which type to use. In such
|
||||
* case, the plugin may apply rules for choosing a path. See for example
|
||||
* {@link JavaPathType#CLASSES} and {@link JavaPathType#MODULES}.</p>
|
||||
*/
|
||||
@Nonnull
|
||||
Set<PathType> getPathTypes();
|
||||
}
|
||||
|
|
|
@ -20,10 +20,13 @@ package org.apache.maven.api.services;
|
|||
|
||||
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<PathType> getPathTypeFilter();
|
||||
|
||||
@Nonnull
|
||||
static DependencyResolverRequestBuilder builder() {
|
||||
return new DependencyResolverRequestBuilder();
|
||||
|
@ -88,6 +101,8 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest {
|
|||
class DependencyResolverRequestBuilder extends DependencyCollectorRequestBuilder {
|
||||
PathScope pathScope;
|
||||
|
||||
Predicate<PathType> pathTypeFilter;
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public DependencyResolverRequestBuilder session(@Nonnull Session session) {
|
||||
|
@ -158,16 +173,53 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest {
|
|||
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<PathType> 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<PathType> desiredTypes) {
|
||||
return pathTypeFilter(desiredTypes::contains);
|
||||
}
|
||||
|
||||
@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<PathType> pathTypeFilter;
|
||||
|
||||
DefaultDependencyResolverRequest(
|
||||
Session session,
|
||||
Project project,
|
||||
|
@ -176,9 +228,11 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest {
|
|||
Collection<DependencyCoordinate> dependencies,
|
||||
Collection<DependencyCoordinate> managedDependencies,
|
||||
boolean verbose,
|
||||
PathScope pathScope) {
|
||||
PathScope pathScope,
|
||||
Predicate<PathType> 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 +243,11 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest {
|
|||
public PathScope getPathScope() {
|
||||
return pathScope;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<PathType> getPathTypeFilter() {
|
||||
return pathTypeFilter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,11 @@ package org.apache.maven.api.services;
|
|||
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<Node> 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<Path> 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}.
|
||||
*
|
||||
* <p><b>Design note:</b>
|
||||
* 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}.</p>
|
||||
*
|
||||
* @return file paths to place on the different tool options
|
||||
*/
|
||||
@Nonnull
|
||||
Map<PathType, List<Path>> getDispatchedPaths();
|
||||
|
||||
@Nonnull
|
||||
Map<Dependency, Path> 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<String> formatOption(PathType type) {
|
||||
List<Path> paths = getDispatchedPaths().get(type);
|
||||
if (paths != null) {
|
||||
String option = type.option(paths);
|
||||
if (!option.isEmpty()) {
|
||||
return Optional.of(option);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <em>should</em> be added to the classpath depends on other
|
||||
* dependency properties.
|
||||
*
|
||||
* @return if the artifact <em>can</em> be added to the class path
|
||||
*
|
||||
* @deprecated A value of {@code true} does not mean that the dependency <em>should</em>
|
||||
* be placed on the classpath. See {@code JavaPathType} instead for better analysis.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean isAddedToClasspath();
|
||||
}
|
||||
|
|
|
@ -77,11 +77,13 @@ public class ArtifactHandlerMock implements ArtifactHandler {
|
|||
return language;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setAddedToClasspath(boolean addedToClasspath) {
|
||||
this.addedToClasspath = addedToClasspath;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean isAddedToClasspath() {
|
||||
return addedToClasspath;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ class TestArtifactHandler implements ArtifactHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean isAddedToClasspath() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ public class DefaultArtifactHandler implements ArtifactHandler {
|
|||
|
||||
private String language;
|
||||
|
||||
@Deprecated
|
||||
private boolean addedToClasspath;
|
||||
|
||||
/**
|
||||
|
@ -146,10 +147,12 @@ public class DefaultArtifactHandler implements ArtifactHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean isAddedToClasspath() {
|
||||
return addedToClasspath;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setAddedToClasspath(final boolean addedToClasspath) {
|
||||
this.addedToClasspath = addedToClasspath;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Map;
|
|||
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;
|
||||
|
@ -72,7 +73,8 @@ public class DefaultArtifactHandlerManager extends AbstractEventSpy implements A
|
|||
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)
|
||||
|
|
|
@ -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.repository.internal.type.DefaultType;
|
||||
|
@ -45,8 +46,8 @@ class TypeRegistryAdapter implements ArtifactTypeRegistry {
|
|||
type.getLanguage(),
|
||||
type.getExtension(),
|
||||
type.getClassifier(),
|
||||
type.isBuildPathConstituent(),
|
||||
type.isIncludesDependencies());
|
||||
type.isIncludesDependencies(),
|
||||
type.getPathTypes().toArray(new PathType[0]));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.Objects;
|
|||
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;
|
||||
|
@ -353,7 +354,8 @@ public abstract class AbstractSession implements InternalSession {
|
|||
@Override
|
||||
public Map<Artifact, Path> resolveArtifacts(Artifact... artifacts) {
|
||||
ArtifactCoordinateFactory acf = getService(ArtifactCoordinateFactory.class);
|
||||
List<ArtifactCoordinate> coords = map(Arrays.asList(artifacts), a -> acf.create(this, a));
|
||||
List<ArtifactCoordinate> coords =
|
||||
Arrays.stream(artifacts).map(a -> acf.create(this, a)).collect(Collectors.toList());
|
||||
return resolveArtifacts(coords);
|
||||
}
|
||||
|
||||
|
@ -502,6 +504,34 @@ public abstract class AbstractSession implements InternalSession {
|
|||
.getPaths();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PathType, List<Path>> resolveDependencies(
|
||||
@Nonnull DependencyCoordinate dependency,
|
||||
@Nonnull PathScope scope,
|
||||
@Nonnull Collection<PathType> desiredTypes) {
|
||||
return getService(DependencyResolver.class)
|
||||
.resolve(DependencyResolverRequest.builder()
|
||||
.session(this)
|
||||
.dependency(dependency)
|
||||
.pathScope(scope)
|
||||
.pathTypeFilter(desiredTypes)
|
||||
.build())
|
||||
.getDispatchedPaths();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PathType, List<Path>> resolveDependencies(
|
||||
@Nonnull Project project, @Nonnull PathScope scope, @Nonnull Collection<PathType> 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);
|
||||
|
|
|
@ -34,6 +34,7 @@ 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 String key;
|
||||
|
|
|
@ -21,24 +21,23 @@ package org.apache.maven.internal.impl;
|
|||
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.Session;
|
||||
import org.apache.maven.api.services.*;
|
||||
import org.apache.maven.lifecycle.LifecycleExecutionException;
|
||||
import org.apache.maven.lifecycle.internal.LifecycleDependencyResolver;
|
||||
import org.apache.maven.project.DependencyResolutionResult;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.eclipse.aether.graph.DependencyFilter;
|
||||
import org.eclipse.aether.graph.DependencyNode;
|
||||
|
||||
|
@ -69,106 +68,43 @@ public class DefaultDependencyResolver implements DependencyResolver {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects, flattens and resolves the dependencies.
|
||||
*
|
||||
* @param request the request to resolve
|
||||
* @return the result of the resolution
|
||||
*/
|
||||
@Override
|
||||
public DependencyResolverResult resolve(DependencyResolverRequest request)
|
||||
throws DependencyCollectorException, DependencyResolverException, ArtifactResolverException {
|
||||
nonNull(request, "request");
|
||||
Session session = InternalSession.from(request.getSession());
|
||||
|
||||
InternalSession session =
|
||||
InternalSession.from(nonNull(request, "request").getSession());
|
||||
Predicate<PathType> filter = request.getPathTypeFilter();
|
||||
PathModularizationCache cache = new PathModularizationCache(); // TODO: should be project-wide cache.
|
||||
DependencyCollectorResult collectorResult =
|
||||
session.getService(DependencyCollector.class).collect(request);
|
||||
List<Node> nodes = flatten(session, collectorResult.getRoot(), request.getPathScope());
|
||||
List<Dependency> deps =
|
||||
nodes.stream().map(Node::getDependency).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
List<ArtifactCoordinate> coordinates =
|
||||
deps.stream().map(Artifact::toCoordinate).collect(Collectors.toList());
|
||||
List<ArtifactCoordinate> coordinates = nodes.stream()
|
||||
.map(Node::getDependency)
|
||||
.filter(Objects::nonNull)
|
||||
.map(Artifact::toCoordinate)
|
||||
.collect(Collectors.toList());
|
||||
Map<Artifact, Path> artifacts = session.resolveArtifacts(coordinates);
|
||||
Map<Dependency, Path> dependencies = new LinkedHashMap<>();
|
||||
List<Path> paths = new ArrayList<>();
|
||||
for (Dependency d : deps) {
|
||||
Path path = artifacts.get(d);
|
||||
if (dependencies.put(d, path) != null) {
|
||||
throw new IllegalStateException("Duplicate key");
|
||||
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<DependencyNode> stream(DependencyNode node) {
|
||||
return Stream.concat(Stream.of(node), node.getChildren().stream().flatMap(this::stream));
|
||||
}
|
||||
|
||||
private DependencyResolutionResult resolveDependencies(Session session, Project project, PathScope scope) {
|
||||
Collection<String> toResolve = toScopes(scope);
|
||||
try {
|
||||
LifecycleDependencyResolver lifecycleDependencyResolver =
|
||||
session.getService(Lookup.class).lookup(LifecycleDependencyResolver.class);
|
||||
return lifecycleDependencyResolver.getProjectDependencyResolutionResult(
|
||||
getMavenProject(project),
|
||||
toResolve,
|
||||
toResolve,
|
||||
InternalSession.from(session).getMavenSession(),
|
||||
false,
|
||||
Collections.emptySet());
|
||||
} catch (LifecycleExecutionException e) {
|
||||
throw new DependencyResolverException("Unable to resolve project dependencies", e);
|
||||
}
|
||||
}
|
||||
|
||||
private MavenProject getMavenProject(Project project) {
|
||||
return ((DefaultProject) project).getProject();
|
||||
}
|
||||
|
||||
private Collection<String> toScopes(PathScope scope) {
|
||||
return map(scope.dependencyScopes(), DependencyScope::id);
|
||||
}
|
||||
|
||||
static class DefaultDependencyResolverResult implements DependencyResolverResult {
|
||||
private final List<Exception> exceptions;
|
||||
private final Node root;
|
||||
private final List<Node> nodes;
|
||||
private final List<Path> paths;
|
||||
private final Map<Dependency, Path> dependencies;
|
||||
|
||||
DefaultDependencyResolverResult(
|
||||
List<Exception> exceptions,
|
||||
Node root,
|
||||
List<Node> nodes,
|
||||
List<Path> paths,
|
||||
Map<Dependency, Path> dependencies) {
|
||||
this.exceptions = exceptions;
|
||||
this.root = root;
|
||||
this.nodes = nodes;
|
||||
this.paths = paths;
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Exception> getExceptions() {
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Node> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Dependency, Path> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
private static DependencyResolverException cannotReadModuleInfo(final Path path, final IOException cause) {
|
||||
return new DependencyResolverException("Cannot read module information of " + path, cause);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* 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:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #addOutputDirectory(Path, Path, PathModularizationCache)} (optional)</li>
|
||||
* <li>{@link #addDependency(Node, Dependency, Predicate, Path, PathModularizationCache)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see DefaultDependencyResolver#resolve(DependencyResolverRequest)
|
||||
*/
|
||||
class DefaultDependencyResolverResult implements DependencyResolverResult {
|
||||
/**
|
||||
* The exceptions that occurred while building the dependency graph.
|
||||
*/
|
||||
private final List<Exception> exceptions;
|
||||
|
||||
/**
|
||||
* The root node of the dependency graph.
|
||||
*/
|
||||
private final Node root;
|
||||
|
||||
/**
|
||||
* The ordered list of the flattened dependency nodes.
|
||||
*/
|
||||
private final List<Node> nodes;
|
||||
|
||||
/**
|
||||
* The file paths of all dependencies, regardless on which Java tool option those paths should be placed.
|
||||
*/
|
||||
private final List<Path> paths;
|
||||
|
||||
/**
|
||||
* The file paths of all dependencies, dispatched according the Java options where to place them.
|
||||
*/
|
||||
private final Map<PathType, List<Path>> dispatchedPaths;
|
||||
|
||||
/**
|
||||
* The dependencies together with the path to each dependency.
|
||||
*/
|
||||
private final Map<Dependency, Path> 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, Predicate, 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<Exception> exceptions, Node root, 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(PathType type, 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.
|
||||
*
|
||||
* <ul>
|
||||
* <li>If the test output directory is modular, then:
|
||||
* <ul>
|
||||
* <li>If a test module name is identical to a main module name,
|
||||
* place the test directory in a {@code --patch-module} option.</li>
|
||||
* <li>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.</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>Otherwise (test output contains no module information), then:
|
||||
* <ul>
|
||||
* <li>If the main output is on the module-path, place the test output
|
||||
* on a {@code --patch-module} option.</li>
|
||||
* <li>Otherwise (main output on the class-path), place the test output on the class-path too.</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* TODO: this is currently not called
|
||||
*/
|
||||
void addOutputDirectory(Path main, Path test, 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;
|
||||
PathModularization testModules = cache.getModuleInfo(test);
|
||||
boolean isModuleHierarchy = outputModules.isModuleHierarchy() || testModules.isModuleHierarchy();
|
||||
for (String moduleName : outputModules.getModuleNames().values()) {
|
||||
Path subdir = test;
|
||||
if (isModuleHierarchy) {
|
||||
// If module hierarchy is used, the directory names shall be the module names.
|
||||
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 (Map.Entry<Path, String> 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(Node node, Dependency dep, Predicate<PathType> filter, Path path, 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.
|
||||
*/
|
||||
// DependencyProperties properties = dep.getDependencyProperties();
|
||||
Set<PathType> 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<Path, String> 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<Path, String> 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.
|
||||
}
|
||||
}
|
||||
addPathElement(cache.selectPathType(pathTypes, filter, path).orElse(PathType.UNRESOLVED), path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given set of path types contains at least one patch for a module.
|
||||
*/
|
||||
private boolean containsPatches(Set<PathType> 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(String moduleName, 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(String group, String artifact) throws IOException {
|
||||
for (Map.Entry<Dependency, Path> entry : dependencies.entrySet()) {
|
||||
Dependency dep = entry.getKey();
|
||||
if (group.equals(dep.getGroupId()) && artifact.equals(dep.getArtifactId())) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Exception> getExceptions() {
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Node> getNodes() {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Path> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<PathType, List<Path>> getDispatchedPaths() {
|
||||
return dispatchedPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Dependency, Path> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ import java.util.Optional;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.LanguageRegistry;
|
||||
|
@ -93,8 +94,9 @@ public class DefaultTypeRegistry extends AbstractEventSpy implements TypeRegistr
|
|||
languageRegistry.require(handler.getLanguage()),
|
||||
handler.getExtension(),
|
||||
handler.getClassifier(),
|
||||
handler.isAddedToClasspath(),
|
||||
handler.isIncludesDependencies());
|
||||
handler.isIncludesDependencies(),
|
||||
JavaPathType.CLASSES,
|
||||
JavaPathType.MODULES);
|
||||
}
|
||||
return type;
|
||||
});
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @see #getModuleNames()
|
||||
*/
|
||||
private final Map<Path, String> 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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p><b>Algorithm:</b>
|
||||
* If the given path is a directory, then there is a choice:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><b>Package hierarchy:</b> 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.</li>
|
||||
* <li><b>Module hierarchy:</b> 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.</li>
|
||||
* </ul>
|
||||
*
|
||||
* Otherwise if the given path is a JAR file, then there is a choice:
|
||||
* <ul>
|
||||
* <li>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.</li>
|
||||
* <li>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.</li>
|
||||
* </ul>
|
||||
*
|
||||
* 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(Path path, 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)) {
|
||||
Map<Path, String> names = new HashMap<>();
|
||||
try (Stream<Path> 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())) {
|
||||
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.
|
||||
Manifest mf = jar.getManifest();
|
||||
if (mf != null) {
|
||||
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(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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*/
|
||||
@Nonnull
|
||||
public Map<Path, String> getModuleNames() {
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the dependency contains a module of the given name.
|
||||
*/
|
||||
public boolean containsModule(String name) {
|
||||
return descriptors.containsValue(name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
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<Path, PathModularization> 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<Path, PathType> 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(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(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 collection.
|
||||
* This method does not handle the patch-module paths, because the patches
|
||||
* depend on which modules have been previously added on the module-paths.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* @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<PathType> selectPathType(Set<PathType> types, Predicate<PathType> filter, 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);
|
||||
}
|
||||
}
|
|
@ -62,6 +62,7 @@ class TransformedArtifactHandler implements ArtifactHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean isAddedToClasspath() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -32,12 +32,14 @@ import java.util.Map;
|
|||
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 class MavenProject implements Cloneable {
|
|||
return testCompileSourceRoots;
|
||||
}
|
||||
|
||||
public List<String> getCompileClasspathElements() throws DependencyResolutionRequiredException {
|
||||
List<String> list = new ArrayList<>(getArtifacts().size() + 1);
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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 let the scope handler deal with this
|
||||
private static boolean isTestPathElement(final String scope) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<String> getClasspathElements(final Predicate<String> scopeFilter, final boolean includeTestDir)
|
||||
throws DependencyResolutionRequiredException {
|
||||
final List<String> list = new ArrayList<>(getArtifacts().size() + 2);
|
||||
if (includeTestDir) {
|
||||
String d = getBuild().getTestOutputDirectory();
|
||||
if (d != null) {
|
||||
list.add(d);
|
||||
}
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
/**
|
||||
* 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<String> getCompileClasspathElements() throws DependencyResolutionRequiredException {
|
||||
return getClasspathElements(MavenProject::isCompilePathElement, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<String> getTestClasspathElements() throws DependencyResolutionRequiredException {
|
||||
List<String> list = new ArrayList<>(getArtifacts().size() + 2);
|
||||
|
||||
String d = getBuild().getTestOutputDirectory();
|
||||
if (d != null) {
|
||||
list.add(d);
|
||||
}
|
||||
|
||||
d = getBuild().getOutputDirectory();
|
||||
if (d != null) {
|
||||
list.add(d);
|
||||
}
|
||||
|
||||
for (Artifact a : getArtifacts()) {
|
||||
if (a.getArtifactHandler().isAddedToClasspath()) {
|
||||
addArtifactPath(a, list);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
return getClasspathElements(MavenProject::isTestPathElement, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<String> getRuntimeClasspathElements() throws DependencyResolutionRequiredException {
|
||||
List<String> 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
|
||||
&& (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope()))) {
|
||||
addArtifactPath(a, list);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
return getClasspathElements(MavenProject::isRuntimePathElement, false);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
@ -1111,13 +1142,6 @@ public class MavenProject implements Cloneable {
|
|||
lifecyclePhases.addAll(project.lifecyclePhases);
|
||||
}
|
||||
|
||||
private void addArtifactPath(Artifact artifact, List<String> 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 class MavenProject implements Cloneable {
|
|||
// 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 class MavenProject implements Cloneable {
|
|||
|
||||
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 class MavenProject implements Cloneable {
|
|||
|
||||
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 class MavenProject implements Cloneable {
|
|||
|
||||
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 class MavenProject implements Cloneable {
|
|||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ public class PluginArtifact extends DefaultArtifact implements ArtifactWithDepen
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean isAddedToClasspath() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ public class ProjectArtifact extends DefaultArtifact implements ArtifactWithDepe
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean isAddedToClasspath() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import javax.inject.Inject;
|
|||
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 org.junit.jupiter.api.Test;
|
|||
|
||||
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 @@ class TestApi {
|
|||
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 @@ class TestApi {
|
|||
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,49 @@ class TestApi {
|
|||
|
||||
@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<Path> paths = session.resolveDependencies(session.createDependencyCoordinate(coord));
|
||||
List<Path> paths = session.resolveDependencies(coord);
|
||||
|
||||
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());
|
||||
|
||||
// JUnit has an "Automatic-Module-Name", so it appears on the module path.
|
||||
Map<PathType, List<Path>> dispatched = session.resolveDependencies(
|
||||
coord, PathScope.TEST_COMPILE, Arrays.asList(JavaPathType.CLASSES, JavaPathType.MODULES));
|
||||
List<Path> classes = dispatched.get(JavaPathType.CLASSES);
|
||||
List<Path> modules = dispatched.get(JavaPathType.MODULES);
|
||||
List<Path> unresolved = dispatched.get(PathType.UNRESOLVED);
|
||||
assertEquals(3, dispatched.size());
|
||||
assertEquals(1, unresolved.size());
|
||||
assertEquals(8, classes.size()); // "plexus.pom" and "junit.jar" are excluded.
|
||||
assertEquals(1, modules.size());
|
||||
assertEquals("plexus-1.0.11.pom", unresolved.get(0).getFileName().toString());
|
||||
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);
|
||||
unresolved = dispatched.get(PathType.UNRESOLVED);
|
||||
assertEquals(2, dispatched.size());
|
||||
assertEquals(1, unresolved.size());
|
||||
assertEquals(9, classes.size());
|
||||
assertNull(modules);
|
||||
assertTrue(paths.containsAll(classes));
|
||||
assertEquals("plexus-1.0.11.pom", unresolved.get(0).getFileName().toString());
|
||||
}
|
||||
|
||||
@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");
|
||||
|
|
|
@ -65,6 +65,7 @@ class TestArtifactHandler implements ArtifactHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean isAddedToClasspath() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ public class ArtifactDescriptorReaderDelegate {
|
|||
ArtifactType stereotype = stereotypes.get(dependency.getType());
|
||||
if (stereotype == null) {
|
||||
// TODO: this here is fishy
|
||||
stereotype = new DefaultType(dependency.getType(), Language.NONE, "", null, false, false);
|
||||
stereotype = new DefaultType(dependency.getType(), Language.NONE, "", null, false);
|
||||
}
|
||||
|
||||
boolean system = dependency.getSystemPath() != null
|
||||
|
|
|
@ -18,11 +18,12 @@
|
|||
*/
|
||||
package org.apache.maven.repository.internal.type;
|
||||
|
||||
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.apache.maven.repository.internal.artifact.MavenArtifactProperties;
|
||||
import org.eclipse.aether.artifact.ArtifactProperties;
|
||||
|
@ -40,8 +41,8 @@ public class DefaultType implements Type, ArtifactType {
|
|||
private final Language language;
|
||||
private final String extension;
|
||||
private final String classifier;
|
||||
private final boolean buildPathConstituent;
|
||||
private final boolean includesDependencies;
|
||||
private final Set<PathType> pathTypes;
|
||||
private final Map<String, String> properties;
|
||||
|
||||
public DefaultType(
|
||||
|
@ -49,20 +50,22 @@ public class DefaultType implements Type, ArtifactType {
|
|||
Language language,
|
||||
String extension,
|
||||
String classifier,
|
||||
boolean buildPathConstituent,
|
||||
boolean includesDependencies) {
|
||||
boolean includesDependencies,
|
||||
PathType... pathTypes) {
|
||||
this.id = requireNonNull(id, "id");
|
||||
this.language = requireNonNull(language, "language");
|
||||
this.extension = requireNonNull(extension, "extension");
|
||||
this.classifier = classifier;
|
||||
this.buildPathConstituent = buildPathConstituent;
|
||||
this.includesDependencies = includesDependencies;
|
||||
this.pathTypes = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(pathTypes)));
|
||||
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
properties.put(ArtifactProperties.TYPE, id);
|
||||
properties.put(ArtifactProperties.LANGUAGE, language.id());
|
||||
properties.put(MavenArtifactProperties.INCLUDES_DEPENDENCIES, Boolean.toString(includesDependencies));
|
||||
properties.put(MavenArtifactProperties.CONSTITUTES_BUILD_PATH, Boolean.toString(buildPathConstituent));
|
||||
properties.put(
|
||||
MavenArtifactProperties.CONSTITUTES_BUILD_PATH,
|
||||
String.valueOf(this.pathTypes.contains(JavaPathType.CLASSES)));
|
||||
this.properties = Collections.unmodifiableMap(properties);
|
||||
}
|
||||
|
||||
|
@ -91,16 +94,15 @@ public class DefaultType implements Type, ArtifactType {
|
|||
return classifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuildPathConstituent() {
|
||||
return this.buildPathConstituent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIncludesDependencies() {
|
||||
return this.includesDependencies;
|
||||
}
|
||||
|
||||
public Set<PathType> getPathTypes() {
|
||||
return this.pathTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getProperties() {
|
||||
return properties;
|
||||
|
|
|
@ -23,6 +23,7 @@ import javax.inject.Named;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.maven.api.JavaPathType;
|
||||
import org.apache.maven.api.Language;
|
||||
import org.apache.maven.api.Type;
|
||||
import org.apache.maven.api.spi.TypeProvider;
|
||||
|
@ -37,18 +38,31 @@ public class DefaultTypeProvider implements TypeProvider {
|
|||
|
||||
public Collection<DefaultType> types() {
|
||||
return Arrays.asList(
|
||||
new DefaultType("bom", Language.NONE, "pom", null, false, false),
|
||||
new DefaultType("pom", Language.NONE, "pom", null, false, false),
|
||||
new DefaultType("maven-plugin", Language.JAVA_FAMILY, "jar", null, true, false),
|
||||
new DefaultType("jar", Language.JAVA_FAMILY, "jar", null, true, false),
|
||||
new DefaultType("ejb", Language.JAVA_FAMILY, "jar", null, true, false),
|
||||
new DefaultType("ejb-client", Language.JAVA_FAMILY, "jar", "client", true, false),
|
||||
new DefaultType("test-jar", Language.JAVA_FAMILY, "jar", "tests", true, false),
|
||||
new DefaultType("javadoc", Language.JAVA_FAMILY, "jar", "javadoc", true, false),
|
||||
new DefaultType("java-source", Language.JAVA_FAMILY, "jar", "sources", false, false),
|
||||
new DefaultType("war", Language.JAVA_FAMILY, "war", null, false, true),
|
||||
new DefaultType("ear", Language.JAVA_FAMILY, "ear", null, false, true),
|
||||
new DefaultType("rar", Language.JAVA_FAMILY, "rar", null, false, true),
|
||||
new DefaultType("par", Language.JAVA_FAMILY, "par", null, false, true));
|
||||
// Maven types
|
||||
new DefaultType(Type.POM, Language.NONE, "pom", null, false),
|
||||
new DefaultType(Type.BOM, Language.NONE, "pom", null, false),
|
||||
new DefaultType(Type.MAVEN_PLUGIN, Language.JAVA_FAMILY, "jar", null, false, JavaPathType.CLASSES),
|
||||
// Java types
|
||||
new DefaultType(
|
||||
Type.JAR, Language.JAVA_FAMILY, "jar", null, false, JavaPathType.CLASSES, JavaPathType.MODULES),
|
||||
new DefaultType(Type.JAVADOC, Language.JAVA_FAMILY, "jar", "javadoc", false, JavaPathType.CLASSES),
|
||||
new DefaultType(Type.JAVA_SOURCE, Language.JAVA_FAMILY, "jar", "sources", false),
|
||||
new DefaultType(
|
||||
Type.TEST_JAR,
|
||||
Language.JAVA_FAMILY,
|
||||
"jar",
|
||||
"tests",
|
||||
false,
|
||||
JavaPathType.CLASSES,
|
||||
JavaPathType.PATCH_MODULE),
|
||||
new DefaultType(Type.MODULAR_JAR, Language.JAVA_FAMILY, "jar", null, false, JavaPathType.MODULES),
|
||||
new DefaultType(Type.CLASSPATH_JAR, Language.JAVA_FAMILY, "jar", null, false, JavaPathType.CLASSES),
|
||||
// j2ee types
|
||||
new DefaultType("ejb", Language.JAVA_FAMILY, "jar", null, false, JavaPathType.CLASSES),
|
||||
new DefaultType("ejb-client", Language.JAVA_FAMILY, "jar", "client", false, JavaPathType.CLASSES),
|
||||
new DefaultType("war", Language.JAVA_FAMILY, "war", null, true),
|
||||
new DefaultType("ear", Language.JAVA_FAMILY, "ear", null, true),
|
||||
new DefaultType("rar", Language.JAVA_FAMILY, "rar", null, true),
|
||||
new DefaultType("par", Language.JAVA_FAMILY, "par", null, true));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue