Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 101 additions & 28 deletions api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
*/
package org.apache.maven.api;

import javax.tools.DocumentationTool;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

api shouldn't depend on that since it is a generic path setup and there we make it depending on a single consumer so look fishy and not very promishing to be as generic as intended

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic API is the PathType interface. This dependency appears in th JavaPathType enumeration, which is the specialization for the Java tools.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok for me if the name reflects it so something like JavaxToolPathType - or whatever makes it explicit. JavaPathType is way more generic IMHO.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Java" here refers to standard Java as defined by Oracle (other entities must use other names, e.g. "Jakarta"). The use of standard javax.tools API should not block non-standard Java tools to be added to this JavaPathType enumeration if desired, because Location is an interface with 2 non-default methods easy to implement (getName() and isOutputLocation()), and the proposed JavaPathType.location() property is Optional anyway.

The close connection to javax.tools API may actually be desirable because contrarily to other API, javax.tools is updated immediately when new Java features requires compiler changes. For example, javax.tools has been updated in Java 9 with the addition of new methods specific to modules management. By contrast, Maven and the Plexus compiler did not really reflected that evolution as far as I can see.

import javax.tools.JavaFileManager;
import javax.tools.StandardLocation;

import java.io.File;
import java.nio.file.Path;
import java.util.Objects;
Expand All @@ -40,6 +44,13 @@
* <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
Expand All @@ -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,
Expand All @@ -63,16 +75,17 @@ public enum JavaPathType implements PathType {
* class-path.</li>
* </ul>
*/
CLASSES("--class-path"),
CLASSES(StandardLocation.CLASS_PATH, "--class-path"),
Comment thread
gnodet marked this conversation as resolved.

/**
* 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
Expand All @@ -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.
Expand All @@ -146,6 +165,13 @@ public static Modular patchModule(@Nonnull String moduleName) {
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.
*
Expand All @@ -156,17 +182,51 @@ public static Modular patchModule(@Nonnull String moduleName) {
/**
* 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
Expand All @@ -187,31 +247,38 @@ public Optional<String> option() {
*
* @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) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this method should be moved out of the API.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The presence or not of this method depends on the comment below.

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) {
Comment thread
gnodet marked this conversation as resolved.
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() + "]";
Expand Down Expand Up @@ -240,11 +307,6 @@ 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}.
Expand All @@ -256,12 +318,23 @@ public JavaPathType rawType() {
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();
}
Expand Down Expand Up @@ -295,11 +368,11 @@ public Optional<String> option() {
*
* @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);
}

Expand Down
23 changes: 12 additions & 11 deletions api/maven-api-core/src/main/java/org/apache/maven/api/PathType.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ public Optional<String> option() {
}

@Override
public String option(Iterable<? extends Path> paths) {
return "";
public String[] option(Iterable<? extends Path> paths) {
return new String[0];
}
};

Expand Down Expand Up @@ -94,23 +94,24 @@ public String option(Iterable<? extends Path> paths) {
* 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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this method should be moved out of the API.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method is proposed here for two reasons: code reuse, and because the method behaviour depends on the option rather than the plugin using it.

Code reuse

The use of this method would be shared by many plugins. For example, the same --class-path option is used by java, javac, javadoc, javap, jdeprscan, jdeps, jmod and jshell. In current Maven architecture, those tools are handled by independent plugins. This method reduces the need to repeat the same code in all plugins.

Note: this strategy relies on Oracle using consistently the same option names for all tools. It seems to be the case for all tools except serialver, provided that we use the modern form (e.g. --class-path instead of -cp).

Who defines the behaviour

The behaviour of this method depends on the option rather than the plugin. For example, JavaPathType.CLASSES formats the given list of files as --class-path <the files>. But JavaPathType.patchModule("org.my.module") formats the same list of files as --patch-module org.my.module=<the files>. This rule is applied consistently in at least java, javac and javadoc. As we can see, the actual work done by this method is determined by the option, not by the plugin, which is why the method appears in PathType: for allowing the implementation to be option-dependent.


/**
* Returns the name of this path type. For example, if this path type
Expand All @@ -122,7 +123,7 @@ public String option(Iterable<? extends Path> paths) {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
@Experimental
public interface Toolchain {
/**
* get the type of toolchain.
* Gets the type of toolchain.
*
* @return the toolchain type
*/
Expand All @@ -47,7 +47,8 @@ public interface Toolchain {
/**
* Let the toolchain decide if it matches requirements defined
* in the toolchain plugin configuration.
* @param requirements Map&lt;String, String&gt; 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);
Expand Down
18 changes: 18 additions & 0 deletions api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
Loading