This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/master by this push:
new 583667a869 [MNG-8015] Adjustments in new API related to PathType
(#1501)
583667a869 is described below
commit 583667a869186161221ca9d7b9ef05c7b5ccf55f
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon May 13 11:53:45 2024 +0200
[MNG-8015] Adjustments in new API related to PathType (#1501)
* Javadoc cleanup and replacement of some `System.getProperty("...")` by
more specific standard methods.
* Add Type.PROCESSOR, MODULAR_PROCESSOR and CLASSPATH_PROCESSOR.
* Modification of the path type API:
* Add a `warningForFilenameBasedAutomodules()` method in
`DependencyResolverResult`.
* Add relationships from `JavaPathType` to `javax.tool` location API.
* Modify the `PathType.option(Iterable<? extends Path>)` return type
because the option and the value need to be two separated arguments.
* Fixes according some comments on the pull request.
---
.../java/org/apache/maven/api/JavaPathType.java | 129 ++++++++++++++++-----
.../main/java/org/apache/maven/api/PathType.java | 23 ++--
.../main/java/org/apache/maven/api/Toolchain.java | 5 +-
.../src/main/java/org/apache/maven/api/Type.java | 18 +++
.../main/java/org/apache/maven/api/plugin/Log.java | 68 +++++------
.../java/org/apache/maven/api/plugin/Mojo.java | 13 +--
.../org/apache/maven/api/plugin/MojoException.java | 12 +-
.../api/services/DependencyResolverResult.java | 30 +++--
.../impl/DefaultDependencyResolverResult.java | 38 ++++--
.../maven/internal/impl/PathModularization.java | 41 ++++++-
.../internal/impl/PathModularizationCache.java | 56 ++++++++-
.../internal/impl/DefaultDependencyResolver.java | 4 +-
.../src/main/java/org/fusesource/jansi/Ansi.java | 2 +-
.../src/main/java/org/apache/maven/utils/Os.java | 10 +-
.../internal/type/DefaultTypeProvider.java | 22 ++++
15 files changed, 339 insertions(+), 132 deletions(-)
diff --git
a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java
b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java
index 7f7b2a22e4..43b4ad1f62 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java
@@ -18,6 +18,10 @@
*/
package org.apache.maven.api;
+import javax.tools.DocumentationTool;
+import javax.tools.JavaFileManager;
+import javax.tools.StandardLocation;
+
import java.io.File;
import java.nio.file.Path;
import java.util.Objects;
@@ -40,6 +44,13 @@ import org.apache.maven.api.annotations.Nonnull;
* <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>
*
+ * <h2>Relationship with Java compiler standard location</h2>
+ * This enumeration is closely related to the {@link JavaFileManager.Location}
enumerations.
+ * A difference is that the latter enumerates input and output files, while
{@code JavaPathType}
+ * enumerates only input dependencies. Another difference is that {@code
JavaPathType} contains
+ * some enumeration values used only at runtime and therefore not available in
{@code javax.tool},
+ * such as agent paths.
+ *
* @see
org.apache.maven.api.services.DependencyResolverResult#getDispatchedPaths()
*
* @since 4.0.0
@@ -49,11 +60,12 @@ public enum JavaPathType implements PathType {
/**
* The path identified by the Java {@code --class-path} option.
* Used for compilation, execution and Javadoc among others.
+ * The Java tools location is {@link StandardLocation#CLASS_PATH}.
*
- * <p><b>Context-sensitive interpretation:</b>
+ * <h4>Context-sensitive interpretation</h4>
* 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,
@@ -63,16 +75,17 @@ public enum JavaPathType implements PathType {
* class-path.</li>
* </ul>
*/
- CLASSES("--class-path"),
+ CLASSES(StandardLocation.CLASS_PATH, "--class-path"),
/**
* The path identified by the Java {@code --module-path} option.
* Used for compilation, execution and Javadoc among others.
+ * The Java tools location is {@link StandardLocation#MODULE_PATH}.
*
- * <p><b>Context-sensitive interpretation:</b>
+ * <h4>Context-sensitive interpretation</h4>
* 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
@@ -84,57 +97,63 @@ public enum JavaPathType implements PathType {
* {@code --module-path} option.</li>
* </ul>
*/
- MODULES("--module-path"),
+ MODULES(StandardLocation.MODULE_PATH, "--module-path"),
/**
* The path identified by the Java {@code --upgrade-module-path} option.
+ * The Java tools location is {@link StandardLocation#UPGRADE_MODULE_PATH}.
*/
- UPGRADE_MODULES("--upgrade-module-path"),
+ UPGRADE_MODULES(StandardLocation.UPGRADE_MODULE_PATH,
"--upgrade-module-path"),
/**
* The path identified by the Java {@code --patch-module} option.
+ * The Java tools location is {@link StandardLocation#PATCH_MODULE_PATH}.
+ *
* 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"),
+ PATCH_MODULE(StandardLocation.PATCH_MODULE_PATH, "--patch-module"),
/**
* The path identified by the Java {@code --processor-path} option.
+ * The Java tools location is {@link
StandardLocation#ANNOTATION_PROCESSOR_PATH}.
*/
- PROCESSOR_CLASSES("--processor-path"),
+ PROCESSOR_CLASSES(StandardLocation.ANNOTATION_PROCESSOR_PATH,
"--processor-path"),
/**
* The path identified by the Java {@code --processor-module-path} option.
+ * The Java tools location is {@link
StandardLocation#ANNOTATION_PROCESSOR_MODULE_PATH}.
*/
- PROCESSOR_MODULES("--processor-module-path"),
+ PROCESSOR_MODULES(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH,
"--processor-module-path"),
/**
* The path identified by the Java {@code -agentpath} option.
*/
- AGENT("-agentpath"),
+ AGENT(null, "-agentpath"),
/**
* The path identified by the Javadoc {@code -doclet} option.
+ * The Java tools location is {@link
DocumentationTool.Location#DOCLET_PATH}.
*/
- DOCLET("-doclet"),
+ DOCLET(DocumentationTool.Location.DOCLET_PATH, "-doclet"),
/**
* The path identified by the Javadoc {@code -tagletpath} option.
+ * The Java tools location is {@link
DocumentationTool.Location#TAGLET_PATH}.
*/
- TAGLETS("-tagletpath");
+ TAGLETS(DocumentationTool.Location.TAGLET_PATH, "-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>
+ * <h4>Context-sensitive interpretation</h4>
* 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.
@@ -146,6 +165,13 @@ public enum JavaPathType implements PathType {
return PATCH_MODULE.new Modular(moduleName);
}
+ /**
+ * The {@code javax.tool} enumeration value corresponding to this {@code
JavaPathType}, or {@code null} if none.
+ *
+ * @see #location()
+ */
+ private final JavaFileManager.Location location;
+
/**
* The tools option for this path, or {@code null} if none.
*
@@ -156,17 +182,51 @@ public enum JavaPathType implements PathType {
/**
* Creates a new enumeration value for a path associated to the given tool
option.
*
+ * @param location the {@code javax.tool} enumeration value, or {@code
null} if none.
* @param option the Java tools option for this path, or {@code null} if
none
*/
- JavaPathType(String option) {
+ JavaPathType(JavaFileManager.Location location, String option) {
+ this.location = location;
this.option = option;
}
+ /**
+ * Returns the unique name of this path type.
+ *
+ * @return the programmatic name of this enumeration value
+ */
@Override
public String id() {
return name();
}
+ /**
+ * Returns the identification of this path in the {@code javax.tool} API.
+ * The value may be an instance of {@link StandardLocation} or {@link
DocumentationTool.Location},
+ * depending which tool will use this location.
+ *
+ * @return the {@code javax.tool} enumeration value corresponding to this
{@code JavaPathType}
+ */
+ public Optional<JavaFileManager.Location> location() {
+ return Optional.ofNullable(location);
+ }
+
+ /**
+ * Returns the path type associated to the given {@code javax.tool}
location.
+ * This method is the converse of {@link #location()}.
+ *
+ * @param location identification of a path in the {@code javax.tool} API
+ * @return Java path type associated to the given location
+ */
+ public static Optional<JavaPathType> valueOf(JavaFileManager.Location
location) {
+ for (JavaPathType type : JavaPathType.values()) {
+ if (location.equals(type.location)) {
+ return Optional.of(type);
+ }
+ }
+ return Optional.empty();
+ }
+
/**
* 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
@@ -187,31 +247,38 @@ public enum JavaPathType implements PathType {
*
* @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
+ * or an empty array 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) {
+ public String[] option(Iterable<? extends Path> paths) {
return format(null, paths);
}
/**
* Implementation shared with {@link Modular}.
*/
- String format(String moduleName, Iterable<? extends Path> paths) {
+ final 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 + '=');
+ String prefix = (moduleName == null) ? "" : (moduleName + '=');
StringJoiner joiner = new StringJoiner(File.pathSeparator, prefix, "");
joiner.setEmptyValue("");
for (Path p : paths) {
joiner.add(p.toString());
}
- return joiner.toString();
+ String value = joiner.toString();
+ if (value.isEmpty()) {
+ return new String[0];
+ }
+ return new String[] {option, value};
}
+ /**
+ * {@return a string representation of this path type for debugging
purposes}.
+ */
@Override
public String toString() {
return "PathType[" + id() + "]";
@@ -240,11 +307,6 @@ public enum JavaPathType implements PathType {
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}.
@@ -256,12 +318,23 @@ public enum JavaPathType implements PathType {
return JavaPathType.this;
}
+ /**
+ * Returns the name of the tool option for this path, including the
module name.
+ *
+ * @return name of the tool option for this path, including the module
name
+ */
+ @Override
+ public String id() {
+ return JavaPathType.this.name() + ":" + moduleName;
+ }
+
/**
* Returns the name of the tool option for this path, not including
the module name.
*
* @return name of the tool option for this path, not including the
module name
*/
@Nonnull
+ @Override
public String name() {
return JavaPathType.this.name();
}
@@ -295,11 +368,11 @@ public enum JavaPathType implements PathType {
*
* @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.
+ * or an empty array if there is no path element.
*/
@Nonnull
@Override
- public String option(Iterable<? extends Path> paths) {
+ public String[] option(Iterable<? extends Path> paths) {
return format(moduleName, paths);
}
diff --git
a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java
b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java
index e7f80cf4a9..4672f6b49f 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java
@@ -61,8 +61,8 @@ public interface PathType {
}
@Override
- public String option(Iterable<? extends Path> paths) {
- return "";
+ public String[] option(Iterable<? extends Path> paths) {
+ return new String[0];
}
};
@@ -94,23 +94,24 @@ public interface PathType {
* The path elements are separated by an option-specific or
platform-specific separator.
* If the given {@code paths} argument contains no element, then this
method returns an empty string.
*
- * <p><b>Examples:</b>
- * If {@code paths} is a list containing two elements, {@code path1} and
{@code path2}, then:
- * </p>
+ * <h4>Examples</h4>
+ * If {@code paths} is a list containing two elements, {@code dir/path1}
and {@code dir/path2}, then:
+ *
* <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>
+ * {@code {"--module-path", "dir/path1:dir/path2"}} on Unix or
+ * {@code {"--module-path", "dir\path1;dir\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>
+ * {@code {"--patch-module", "foo.bar=dir/path1:dir/path2"}} on Unix
or
+ * {@code {"--patch-module", "foo.bar=dir\path1;dir\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.
+ * or an empty array if there is no path element.
*/
@Nonnull
- String option(Iterable<? extends Path> paths);
+ String[] option(Iterable<? extends Path> paths);
/**
* Returns the name of this path type. For example, if this path type
@@ -122,7 +123,7 @@ public interface PathType {
String name();
/**
- * Returns a string representation for this extensible enum describing a
path type.
+ * {@return a string representation for this extensible enum describing a
path type}.
* For example {@code "PathType[PATCH_MODULE:foo.bar]"}.
*/
@Nonnull
diff --git
a/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java
b/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java
index 053f230651..c03358b05d 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java
@@ -30,7 +30,7 @@ import org.apache.maven.api.annotations.Experimental;
@Experimental
public interface Toolchain {
/**
- * get the type of toolchain.
+ * Gets the type of toolchain.
*
* @return the toolchain type
*/
@@ -47,7 +47,8 @@ public interface Toolchain {
/**
* Let the toolchain decide if it matches requirements defined
* in the toolchain plugin configuration.
- * @param requirements Map<String, String> key value pair, may not
be {@code null}
+ *
+ * @param requirements key value pair, may not be {@code null}
* @return {@code true} if the requirements match, otherwise {@code false}
*/
boolean matchesRequirements(Map<String, String> requirements);
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
index c582809450..4d3cb13ea0 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
@@ -81,6 +81,24 @@ public interface Type extends ExtensibleEnum {
*/
String MODULAR_JAR = "modular-jar";
+ /**
+ * Artifact type name for a JAR file that can be placed either on the
annotation processor class-path
+ * or module-path. The path (classes or modules) is chosen by the plugin,
possibly using heuristic rules.
+ */
+ String PROCESSOR = "processor";
+
+ /**
+ * Artifact type name for a JAR file to unconditionally place on the
annotation processor class-path.
+ * If the JAR is modular, its module information are ignored.
+ */
+ String CLASSPATH_PROCESSOR = "classpath-processor";
+
+ /**
+ * Artifact type name for a JAR file to unconditionally place on the
annotation processor module-path.
+ * If the JAR is not modular, then it is loaded by Java as an unnamed
module.
+ */
+ String MODULAR_PROCESSOR = "modular-processor";
+
/**
* Artifact type name for source code packaged in a JAR file.
*/
diff --git
a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java
b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java
index 8fb3a7b947..16a55a8055 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java
@@ -24,8 +24,8 @@ import org.apache.maven.api.annotations.Experimental;
import org.apache.maven.api.annotations.Provider;
/**
- * This interface supplies the API for providing feedback to the user from the
<code>Mojo</code>, using standard
- * <code>Maven</code> channels.<br>
+ * This interface supplies the API for providing feedback to the user from the
{@code Mojo},
+ * using standard Maven channels.
* There should be no big surprises here, although you may notice that the
methods accept
* <code>java.lang.CharSequence</code> rather than
<code>java.lang.String</code>. This is provided mainly as a
* convenience, to enable developers to pass things like
<code>java.lang.StringBuffer</code> directly into the logger,
@@ -37,31 +37,31 @@ import org.apache.maven.api.annotations.Provider;
@Provider
public interface Log {
/**
- * @return true if the <b>debug</b> error level is enabled
+ * {@return true if the <b>debug</b> error level is enabled}.
*/
boolean isDebugEnabled();
/**
- * Send a message to the user in the <b>debug</b> error level.
+ * Sends a message to the user in the <b>debug</b> error level.
*
- * @param content
+ * @param content the message to log
*/
void debug(CharSequence content);
/**
- * Send a message (and accompanying exception) to the user in the
<b>debug</b> error level.<br>
+ * Sends a message (and accompanying exception) to the user in the
<b>debug</b> error level.
* The error's stacktrace will be output when this error level is enabled.
*
- * @param content
- * @param error
+ * @param content the message to log
+ * @param error the error that caused this log
*/
void debug(CharSequence content, Throwable error);
/**
- * Send an exception to the user in the <b>debug</b> error level.<br>
+ * Sends an exception to the user in the <b>debug</b> error level.
* The stack trace for this exception will be output when this error level
is enabled.
*
- * @param error
+ * @param error the error that caused this log
*/
void debug(Throwable error);
@@ -70,31 +70,31 @@ public interface Log {
void debug(Supplier<String> content, Throwable error);
/**
- * @return true if the <b>info</b> error level is enabled
+ * {@return true if the <b>info</b> error level is enabled}.
*/
boolean isInfoEnabled();
/**
- * Send a message to the user in the <b>info</b> error level.
+ * Sends a message to the user in the <b>info</b> error level.
*
- * @param content
+ * @param content the message to log
*/
void info(CharSequence content);
/**
- * Send a message (and accompanying exception) to the user in the
<b>info</b> error level.<br>
+ * Sends a message (and accompanying exception) to the user in the
<b>info</b> error level.
* The error's stacktrace will be output when this error level is enabled.
*
- * @param content
- * @param error
+ * @param content the message to log
+ * @param error the error that caused this log
*/
void info(CharSequence content, Throwable error);
/**
- * Send an exception to the user in the <b>info</b> error level.<br>
+ * Sends an exception to the user in the <b>info</b> error level.
* The stack trace for this exception will be output when this error level
is enabled.
*
- * @param error
+ * @param error the error that caused this log
*/
void info(Throwable error);
@@ -103,31 +103,31 @@ public interface Log {
void info(Supplier<String> content, Throwable error);
/**
- * @return true if the <b>warn</b> error level is enabled
+ * {@return true if the <b>warn</b> error level is enabled}.
*/
boolean isWarnEnabled();
/**
- * Send a message to the user in the <b>warn</b> error level.
+ * Sends a message to the user in the <b>warn</b> error level.
*
- * @param content
+ * @param content the message to log
*/
void warn(CharSequence content);
/**
- * Send a message (and accompanying exception) to the user in the
<b>warn</b> error level.<br>
+ * Sends a message (and accompanying exception) to the user in the
<b>warn</b> error level.
* The error's stacktrace will be output when this error level is enabled.
*
- * @param content
- * @param error
+ * @param content the message to log
+ * @param error the error that caused this log
*/
void warn(CharSequence content, Throwable error);
/**
- * Send an exception to the user in the <b>warn</b> error level.<br>
+ * Sends an exception to the user in the <b>warn</b> error level.
* The stack trace for this exception will be output when this error level
is enabled.
*
- * @param error
+ * @param error the error that caused this log
*/
void warn(Throwable error);
@@ -136,31 +136,31 @@ public interface Log {
void warn(Supplier<String> content, Throwable error);
/**
- * @return true if the <b>error</b> error level is enabled
+ * {@return true if the <b>error</b> error level is enabled}.
*/
boolean isErrorEnabled();
/**
- * Send a message to the user in the <b>error</b> error level.
+ * Sends a message to the user in the <b>error</b> error level.
*
- * @param content
+ * @param content the message to log
*/
void error(CharSequence content);
/**
- * Send a message (and accompanying exception) to the user in the
<b>error</b> error level.<br>
+ * Sends a message (and accompanying exception) to the user in the
<b>error</b> error level.
* The error's stacktrace will be output when this error level is enabled.
*
- * @param content
- * @param error
+ * @param content the message to log
+ * @param error the error that caused this log
*/
void error(CharSequence content, Throwable error);
/**
- * Send an exception to the user in the <b>error</b> error level.<br>
+ * Sends an exception to the user in the <b>error</b> error level.
* The stack trace for this exception will be output when this error level
is enabled.
*
- * @param error
+ * @param error the error that caused this log
*/
void error(Throwable error);
diff --git
a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java
b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java
index 7c9603b0c5..62807378fa 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java
@@ -22,10 +22,9 @@ import org.apache.maven.api.annotations.Consumer;
import org.apache.maven.api.annotations.Experimental;
/**
- * This interface forms the contract required for <code>Mojos</code> to
interact with the <code>Maven</code>
- * infrastructure.<br>
- * It features an <code>execute()</code> method, which triggers the Mojo's
build-process behavior, and can throw
- * a MojoException if error conditions occur.<br>
+ * This interface forms the contract required for Mojos to interact with the
Maven infrastructure.
+ * It features an {@link #execute()} method, which triggers the Mojo's
build-process behavior,
+ * and can throw a {@link MojoException} if error conditions occur.
*
* @since 4.0.0
*/
@@ -34,9 +33,9 @@ import org.apache.maven.api.annotations.Experimental;
@Consumer
public interface Mojo {
/**
- * Perform whatever build-process behavior this <code>Mojo</code>
implements.<br>
- * This is the main trigger for the <code>Mojo</code> inside the
<code>Maven</code> system, and allows
- * the <code>Mojo</code> to communicate errors.
+ * Perform whatever build-process behavior this {@code Mojo} implements.
+ * This is the main trigger for the {@code Mojo} inside the Maven system,
+ * and allows the {@code Mojo} to communicate errors.
*
* @throws MojoException if a problem occurs
*/
diff --git
a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
index b4faf31ceb..2d4b976cee 100644
---
a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
+++
b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
@@ -34,8 +34,8 @@ public class MojoException extends MavenException {
protected String longMessage;
/**
- * Construct a new <code>MojoException</code> exception providing the
source and a short and long message:
- * these messages are used to improve the message written at the end of
Maven build.
+ * Constructs a new {@code MojoException} providing the source and a short
and long message.
+ * These messages are used to improve the message written at the end of
Maven build.
*/
public MojoException(Object source, String shortMessage, String
longMessage) {
super(shortMessage);
@@ -44,22 +44,22 @@ public class MojoException extends MavenException {
}
/**
- * Construct a new <code>MojoExecutionException</code> exception wrapping
an underlying <code>Throwable</code>
- * and providing a <code>message</code>.
+ * Constructs a new {@code MojoException} wrapping an underlying {@code
Throwable}
+ * and providing a {@code message}.
*/
public MojoException(String message, Throwable cause) {
super(message, cause);
}
/**
- * Construct a new <code>MojoExecutionException</code> exception providing
a <code>message</code>.
+ * Constructs a new {@code MojoException} providing a {@code message}.
*/
public MojoException(String message) {
super(message);
}
/**
- * Constructs a new {@code MojoExecutionException} exception wrapping an
underlying {@code Throwable}.
+ * Constructs a new {@code MojoExecutionException} wrapping an underlying
{@code Throwable}.
*
* @param cause the cause which is saved for later retrieval by the {@link
#getCause()} method.
* A {@code null} value is permitted, and indicates that the
cause is nonexistent or unknown.
diff --git
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
index cb1c32031d..9579ad6d17 100644
---
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
+++
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java
@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Optional;
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.annotations.Experimental;
@@ -43,6 +44,8 @@ public interface DependencyResolverResult extends
DependencyCollectorResult {
/**
* 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.
+ * This collection has the same content than {@code
getDependencies.values()} except that it does not contain
+ * null elements.
*
* @return the paths of all dependencies
*/
@@ -55,36 +58,31 @@ public interface DependencyResolverResult extends
DependencyCollectorResult {
* In the case of Java tools, the map may also contain {@code
--patch-module} options, which are
* {@linkplain org.apache.maven.api.JavaPathType#patchModule(String)
handled in a special way}.
*
- * <p><b>Design note:</b>
+ * <h4>Design note</h4>
* 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>
+ * identified by {@link PathType}.
*
* @return file paths to place on the different tool options
*/
@Nonnull
Map<PathType, List<Path>> getDispatchedPaths();
+ /**
+ * {@return all dependencies associated to their paths}.
+ * Some dependencies may be associated to a null value if there is no path
available.
+ */
@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.
+ * If the module-path contains at least one filename-based auto-module,
prepares a warning message.
+ * The module path is the collection of dependencies associated to {@link
JavaPathType#MODULES}.
+ * It is caller's responsibility to send the message to a logger.
*
- * @param type the desired type of path (class-path, module-path, …)
- * @return the option to pass to Java tools
+ * @return warning message if at least one filename-based auto-module was
found
*/
- 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();
- }
+ Optional<String> warningForFilenameBasedAutomodules();
}
diff --git
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java
index 0214ae4c69..baf7b44424 100644
---
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java
+++
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java
@@ -26,6 +26,7 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
@@ -33,6 +34,7 @@ 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.DependencyResolverException;
import org.apache.maven.api.services.DependencyResolverRequest;
import org.apache.maven.api.services.DependencyResolverResult;
@@ -42,8 +44,8 @@ import org.apache.maven.api.services.DependencyResolverResult;
* 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>
+ * <li>{@link #addOutputDirectory(Path, Path)} (optional)</li>
+ * <li>{@link #addDependency(Node, Dependency, Predicate, Path)}</li>
* </ul>
*
* @see DefaultDependencyResolver#resolve(DependencyResolverRequest)
@@ -85,15 +87,22 @@ class DefaultDependencyResolverResult implements
DependencyResolverResult {
*/
private PathModularization outputModules;
+ /**
+ * Cache of module information about each dependency.
+ */
+ private final PathModularizationCache cache;
+
/**
* Creates an initially empty result. Callers should add path elements by
calls
* to {@link #addDependency(Node, Dependency, Predicate, Path,
PathModularizationCache)}.
*
+ * @param cache cache of module information about each dependency
* @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) {
+ DefaultDependencyResolverResult(PathModularizationCache cache,
List<Exception> exceptions, Node root, int count) {
+ this.cache = cache;
this.exceptions = exceptions;
this.root = root;
nodes = new ArrayList<>(count);
@@ -137,18 +146,17 @@ class DefaultDependencyResolverResult implements
DependencyResolverResult {
* </li>
* </ul>
*
- * This method must be invoked before {@link #addDependency(Node,
Dependency, Predicate, Path, PathModularizationCache)}
+ * This method must be invoked before {@link #addDependency(Node,
Dependency, Predicate, Path)}
* if output directories are desired on the class-path or module-path.
* This method can be invoked at most once.
*
* @param main the main output directory, or {@code null} if none
* @param test the test output directory, or {@code null} if none
- * @param cache cache of module information about each dependency
* @throws IOException if an error occurred while reading module
information
*
* TODO: this is currently not called
*/
- void addOutputDirectory(Path main, Path test, PathModularizationCache
cache) throws IOException {
+ void addOutputDirectory(Path main, Path test) throws IOException {
if (outputModules != null) {
throw new IllegalStateException("Output directories must be set
first and only once.");
}
@@ -201,11 +209,9 @@ class DefaultDependencyResolverResult implements
DependencyResolverResult {
* @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 {
+ void addDependency(Node node, Dependency dep, Predicate<PathType> filter,
Path path) throws IOException {
nodes.add(node);
if (dep == null) {
return;
@@ -235,7 +241,7 @@ class DefaultDependencyResolverResult implements
DependencyResolverResult {
cache.getModuleInfo(path).getModuleNames().entrySet()) {
String moduleName = info.getValue();
type = JavaPathType.patchModule(moduleName);
- if (!containsModule(moduleName, cache)) {
+ if (!containsModule(moduleName)) {
/*
* 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.
@@ -288,9 +294,8 @@ class DefaultDependencyResolverResult implements
DependencyResolverResult {
* 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 {
+ private boolean containsModule(String moduleName) throws IOException {
for (Path path : dispatchedPaths.getOrDefault(JavaPathType.MODULES,
Collections.emptyList())) {
if (cache.getModuleInfo(path).containsModule(moduleName)) {
return true;
@@ -345,4 +350,13 @@ class DefaultDependencyResolverResult implements
DependencyResolverResult {
public Map<Dependency, Path> getDependencies() {
return dependencies;
}
+
+ @Override
+ public Optional<String> warningForFilenameBasedAutomodules() {
+ try {
+ return
cache.warningForFilenameBasedAutomodules(dispatchedPaths.get(JavaPathType.MODULES));
+ } catch (IOException e) {
+ throw new DependencyResolverException("Cannot read module
information.", e);
+ }
+ }
}
diff --git
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java
index 44d32a8762..2728fb4aca 100644
---
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java
+++
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java
@@ -24,6 +24,7 @@ import java.io.UncheckedIOException;
import java.lang.module.ModuleDescriptor;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -58,6 +59,11 @@ class PathModularization {
*/
private static final Attributes.Name AUTO_MODULE_NAME = new
Attributes.Name("Automatic-Module-Name");
+ /**
+ * Filename of the path specified at construction time.
+ */
+ private final String filename;
+
/**
* Module information for the path specified at construction time.
* This map is usually either empty if no module was found, or a singleton
map.
@@ -88,6 +94,7 @@ class PathModularization {
* @see #NONE
*/
private PathModularization() {
+ filename = "(none)";
descriptors = Collections.emptyMap();
isModuleHierarchy = false;
}
@@ -128,6 +135,7 @@ class PathModularization {
* @throws IOException if an error occurred while reading the JAR file or
the module descriptor
*/
PathModularization(Path path, boolean resolve) throws IOException {
+ filename = path.getFileName().toString();
if (Files.isDirectory(path)) {
/*
* Package hierarchy: only one module with descriptor at the root.
@@ -213,7 +221,7 @@ class PathModularization {
}
/**
- * Returns the module name declared in the given {@code module-info}
descriptor.
+ * {@return 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
@@ -222,7 +230,7 @@ class PathModularization {
}
/**
- * Returns the type of path detected. The return value is {@link
JavaPathType#MODULES}
+ * {@return 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.
@@ -232,7 +240,21 @@ class PathModularization {
}
/**
- * Returns whether module hierarchy was detected. If false, then package
hierarchy is assumed.
+ * If the module has no name, adds the filename of the JAR file in the
given collection.
+ * This method should be invoked for dependencies placed on {@link
JavaPathType#MODULES}
+ * for preparing a warning asking to not deploy the build artifact on a
public repository.
+ * If the module has an explicit name either with a {@code
module-info.class} file or with
+ * an {@code "Automatic-Module-Name"} attribute in the {@code
META-INF/MANIFEST.MF} file,
+ * then this method does nothing.
+ */
+ public void addIfFilenameBasedAutomodules(Collection<String>
automodulesDetected) {
+ if (descriptors.isEmpty()) {
+ automodulesDetected.add(filename);
+ }
+ }
+
+ /**
+ * {@return whether module hierarchy was detected}. If {@code 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).
@@ -242,7 +264,7 @@ class PathModularization {
}
/**
- * Returns the module names for the path specified at construction time.
+ * {@return 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.
@@ -257,9 +279,18 @@ class PathModularization {
}
/**
- * Returns whether the dependency contains a module of the given name.
+ * {@return whether the dependency contains a module of the given name}.
*/
public boolean containsModule(String name) {
return descriptors.containsValue(name);
}
+
+ /**
+ * {@return a string representation of this object for debugging purposes}.
+ * This string representation may change in any future version.
+ */
+ @Override
+ public String toString() {
+ return getClass().getCanonicalName() + '[' + filename + ']';
+ }
}
diff --git
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java
index e542fed68e..37b7c6bf3d 100644
---
a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java
+++
b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java
@@ -20,10 +20,13 @@ package org.apache.maven.internal.impl;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.StringJoiner;
import java.util.function.Predicate;
import org.apache.maven.api.JavaPathType;
@@ -108,12 +111,18 @@ class PathModularizationCache {
boolean classes = false;
boolean modules = false;
boolean unknown = false;
+ boolean processorClasses = false;
+ boolean processorModules = 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 if (JavaPathType.PROCESSOR_CLASSES.equals(type)) {
+ processorClasses = true;
+ } else if (JavaPathType.PROCESSOR_MODULES.equals(type)) {
+ processorModules = true;
} else {
unknown = true;
}
@@ -126,9 +135,54 @@ class PathModularizationCache {
}
}
}
- if (classes & modules) {
+ /*
+ * If the dependency can be both on the class-path and the
module-path, we need to chose one of these.
+ * The choice done below will overwrite the current `selected` value
because the latter is only the
+ * first value encountered in iteration order, which may be random.
+ */
+ if (classes | modules) {
+ if (classes & modules) {
+ selected = getPathType(path);
+ } else if (classes) {
+ selected = JavaPathType.CLASSES;
+ } else {
+ selected = JavaPathType.MODULES;
+ }
+ } else if (processorClasses & processorModules) {
selected = getPathType(path);
+ if (JavaPathType.CLASSES.equals(selected)) {
+ selected = JavaPathType.PROCESSOR_CLASSES;
+ } else if (JavaPathType.MODULES.equals(selected)) {
+ selected = JavaPathType.PROCESSOR_MODULES;
+ }
}
return Optional.ofNullable(selected);
}
+
+ /**
+ * If the module-path contains a filename-based auto-module, prepares a
warning message.
+ * It is caller's responsibility to send the message to a logger.
+ *
+ * @param modulePaths content of the module path, or {@code null} if none
+ * @return warning message if at least one filename-based auto-module was
found
+ * @throws IOException if an error occurred while reading module
information
+ */
+ Optional<String> warningForFilenameBasedAutomodules(Collection<Path>
modulePaths) throws IOException {
+ if (modulePaths == null) {
+ return Optional.empty();
+ }
+ var automodulesDetected = new ArrayList<String>();
+ for (Path p : modulePaths) {
+
getModuleInfo(p).addIfFilenameBasedAutomodules(automodulesDetected);
+ }
+ if (automodulesDetected.isEmpty()) {
+ return Optional.empty();
+ }
+ var joiner = new StringJoiner(
+ ", ",
+ "Filename-based automodules detected on the module-path: ",
+ "Please don't publish this project to a public artifact
repository.");
+ automodulesDetected.forEach(joiner::add);
+ return Optional.of(joiner.toString());
+ }
}
diff --git
a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java
b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java
index 37eac68cee..254ee13f06 100644
---
a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java
+++
b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java
@@ -91,12 +91,12 @@ public class DefaultDependencyResolver implements
DependencyResolver {
.collect(Collectors.toList());
Map<Artifact, Path> artifacts = session.resolveArtifacts(coordinates);
DefaultDependencyResolverResult result = new
DefaultDependencyResolverResult(
- collectorResult.getExceptions(), collectorResult.getRoot(),
nodes.size());
+ cache, 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);
+ result.addDependency(node, d, filter, path);
} catch (IOException e) {
throw cannotReadModuleInfo(path, e);
}
diff --git a/maven-embedder/src/main/java/org/fusesource/jansi/Ansi.java
b/maven-embedder/src/main/java/org/fusesource/jansi/Ansi.java
index 3bdb850aaf..c0a9f811fb 100644
--- a/maven-embedder/src/main/java/org/fusesource/jansi/Ansi.java
+++ b/maven-embedder/src/main/java/org/fusesource/jansi/Ansi.java
@@ -825,7 +825,7 @@ public class Ansi implements Appendable {
public Ansi newline() {
flushAttributes();
- builder.append(System.getProperty("line.separator"));
+ builder.append(System.lineSeparator());
return this;
}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/utils/Os.java
b/maven-model-builder/src/main/java/org/apache/maven/utils/Os.java
index 3bc84fcec1..3df379a051 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/utils/Os.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/utils/Os.java
@@ -18,6 +18,7 @@
*/
package org.apache.maven.utils;
+import java.io.File;
import java.util.Locale;
import java.util.stream.Stream;
@@ -124,11 +125,6 @@ public class Os {
*/
private static final String DARWIN = "darwin";
- /**
- * The path separator.
- */
- private static final String PATH_SEP =
System.getProperty("path.separator");
-
static {
// Those two public constants are initialized here, as they need all
the private constants
// above to be initialized first, but the code style imposes the
public constants to be
@@ -187,13 +183,13 @@ public class Os {
case FAMILY_NETWARE:
return actualOsName.contains(FAMILY_NETWARE);
case FAMILY_DOS:
- return PATH_SEP.equals(";") && !isFamily(FAMILY_NETWARE,
actualOsName) && !isWindows;
+ return File.pathSeparatorChar == ';' &&
!isFamily(FAMILY_NETWARE, actualOsName) && !isWindows;
case FAMILY_MAC:
return actualOsName.contains(FAMILY_MAC) ||
actualOsName.contains(DARWIN);
case FAMILY_TANDEM:
return actualOsName.contains("nonstop_kernel");
case FAMILY_UNIX:
- return PATH_SEP.equals(":")
+ return File.pathSeparatorChar == ':'
&& !isFamily(FAMILY_OPENVMS, actualOsName)
&& (!isFamily(FAMILY_MAC, actualOsName) ||
actualOsName.endsWith("x"));
case FAMILY_ZOS:
diff --git
a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/DefaultTypeProvider.java
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/DefaultTypeProvider.java
index 8f98250833..a4995aa43a 100644
---
a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/DefaultTypeProvider.java
+++
b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/type/DefaultTypeProvider.java
@@ -58,6 +58,28 @@ public class DefaultTypeProvider implements TypeProvider {
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),
new DefaultType(Type.FATJAR, Language.JAVA_FAMILY, "jar",
null, true, JavaPathType.CLASSES),
+ new DefaultType(
+ Type.PROCESSOR,
+ Language.JAVA_FAMILY,
+ "jar",
+ null,
+ false,
+ JavaPathType.PROCESSOR_CLASSES,
+ JavaPathType.PROCESSOR_MODULES),
+ new DefaultType(
+ Type.MODULAR_PROCESSOR,
+ Language.JAVA_FAMILY,
+ "jar",
+ null,
+ false,
+ JavaPathType.PROCESSOR_MODULES),
+ new DefaultType(
+ Type.CLASSPATH_PROCESSOR,
+ Language.JAVA_FAMILY,
+ "jar",
+ null,
+ false,
+ JavaPathType.PROCESSOR_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),