diff --git a/.github/workflows/maven-verify.yml b/.github/workflows/maven-verify.yml
index 932827cf9..89d9cfdbc 100644
--- a/.github/workflows/maven-verify.yml
+++ b/.github/workflows/maven-verify.yml
@@ -25,3 +25,8 @@ jobs:
build:
name: Verify
uses: apache/maven-gh-actions-shared/.github/workflows/maven-verify.yml@v4
+ with:
+ maven-matrix: '[ "3.6.3", "3.9.7", "4.0.0-beta-3" ]'
+ jdk-matrix: '[ "8", "17", "21" ]'
+ matrix-exclude: '[ { maven: "4.0.0-beta-3", jdk: "8" } ]'
+
diff --git a/maven-plugin-plugin/src/it/v4api/invoker.properties b/maven-plugin-plugin/src/it/v4api/invoker.properties
index 43be5b1d2..e1b693413 100644
--- a/maven-plugin-plugin/src/it/v4api/invoker.properties
+++ b/maven-plugin-plugin/src/it/v4api/invoker.properties
@@ -15,4 +15,5 @@
# specific language governing permissions and limitations
# under the License.
+invoker.java.version = 17+
invoker.goals.1 = clean install
diff --git a/maven-plugin-plugin/src/it/v4api/src/main/java/org/apache/maven/its/v4api/FirstMojo.java b/maven-plugin-plugin/src/it/v4api/src/main/java/org/apache/maven/its/v4api/FirstMojo.java
index 879f3cefa..abab3cee0 100644
--- a/maven-plugin-plugin/src/it/v4api/src/main/java/org/apache/maven/its/v4api/FirstMojo.java
+++ b/maven-plugin-plugin/src/it/v4api/src/main/java/org/apache/maven/its/v4api/FirstMojo.java
@@ -22,13 +22,12 @@
import org.apache.maven.api.MojoExecution;
import org.apache.maven.api.Project;
-import org.apache.maven.api.ResolutionScope;
import org.apache.maven.api.Session;
+import org.apache.maven.api.di.Inject;
+import org.apache.maven.api.di.Named;
import org.apache.maven.api.plugin.Log;
import org.apache.maven.api.plugin.MojoException;
-import org.apache.maven.api.plugin.annotations.Component;
import org.apache.maven.api.plugin.annotations.Execute;
-import org.apache.maven.api.plugin.annotations.LifecyclePhase;
import org.apache.maven.api.plugin.annotations.Mojo;
import org.apache.maven.api.plugin.annotations.Parameter;
import org.apache.maven.api.services.ArtifactInstaller;
@@ -38,15 +37,12 @@
* Test mojo for the v4 api plugin descriptor generation.
* This mojo is not actually runnable because:
* - it's using a custom lifecycle which is not defined
- * - it has a @Component dependency on ArtifactInstaller (hint=test) which does not exist
+ * - it has a @Inject dependency on ArtifactInstaller (hint=test) which does not exist
*
* @since 1.2
*/
-@Mojo(
- name = "first",
- requiresDependencyResolution = ResolutionScope.TEST,
- defaultPhase = LifecyclePhase.INTEGRATION_TEST)
-@Execute(phase = LifecyclePhase.GENERATE_SOURCES, lifecycle = "cobertura")
+@Mojo(name = "first", defaultPhase = "integration-test")
+@Execute(phase = "generate-sources", lifecycle = "cobertura")
public class FirstMojo implements org.apache.maven.api.plugin.Mojo {
/**
@@ -66,23 +62,24 @@ public class FirstMojo implements org.apache.maven.api.plugin.Mojo {
@Parameter(name = "namedParam", alias = "alias")
private String aliasedParam;
- @Component
+ @Inject
private Session session;
- @Component
+ @Inject
private Project project;
- @Component
+ @Inject
private MojoExecution mojo;
- @Component
+ @Inject
private Settings settings;
- @Component
+ @Inject
private Log log;
- @Component(role = ArtifactInstaller.class, hint = "test")
- private Object custom;
+ @Inject
+ @Named("test")
+ private ArtifactInstaller custom;
public void execute() throws MojoException {}
}
diff --git a/maven-plugin-plugin/src/it/v4api/verify.groovy b/maven-plugin-plugin/src/it/v4api/verify.groovy
index 1405e2313..878ab95a3 100644
--- a/maven-plugin-plugin/src/it/v4api/verify.groovy
+++ b/maven-plugin-plugin/src/it/v4api/verify.groovy
@@ -24,8 +24,8 @@ assert descriptorFile.isFile()
def pluginDescriptor = new XmlParser().parse( descriptorFile );
-assert pluginDescriptor.requiredJavaVersion.text() == '1.8'
-assert pluginDescriptor.requiredMavenVersion.text() == '4.0.0-alpha-4'
+assert pluginDescriptor.requiredJavaVersion.text() == '17'
+assert pluginDescriptor.requiredMavenVersion.text() == '4.0.0-beta-3'
def mojo = pluginDescriptor.mojos.mojo.findAll{ it.goal.text() == "first" }[0]
@@ -33,51 +33,12 @@ assert mojo.goal.text() == 'first'
assert mojo.implementation.text() == 'org.apache.maven.its.v4api.FirstMojo'
assert mojo.language.text() == 'java'
assert mojo.description.text().startsWith('Test mojo for the v4 api plugin descriptor generation.')
-assert mojo.requiresDependencyResolution.text() == 'test'
-assert mojo.requiresDependencyCollection.text() == ''
-assert mojo.requiresProject.text() == 'true'
-assert mojo.requiresOnline.text() == 'false'
-assert mojo.requiresDirectInvocation.text() == 'false'
+assert mojo.projectRequired.text() == 'true'
+assert mojo.onlineRequired.text() == 'false'
assert mojo.aggregator.text() == 'false'
-assert mojo.threadSafe.text() == 'false'
assert mojo.phase.text() == 'integration-test'
assert mojo.executePhase.text() == 'generate-sources'
assert mojo.executeLifecycle.text() == 'cobertura'
-assert mojo.v4Api.text() == 'true'
-
-assert mojo.configuration.basedir[0].text() == ''
-assert mojo.configuration.basedir[0].'@implementation' == 'java.nio.file.Path'
-assert mojo.configuration.basedir[0].'@default-value' == '${basedir}'
-
-assert mojo.configuration.touchFile[0].text() == '${first.touchFile}'
-assert mojo.configuration.touchFile[0].'@implementation' == 'java.nio.file.Path'
-assert mojo.configuration.touchFile[0].'@default-value' == '${project.build.directory}/touch.txt'
-
-assert mojo.requirements.requirement.size() == 6
-
-assert mojo.requirements.requirement[0].role.text() == 'org.apache.maven.api.services.ArtifactInstaller'
-assert mojo.requirements.requirement[0].'role-hint'.text() == 'test'
-assert mojo.requirements.requirement[0].'field-name'.text() == 'custom'
-
-assert mojo.requirements.requirement[1].role.text() == 'org.apache.maven.api.plugin.Log'
-assert mojo.requirements.requirement[1].'role-hint'.isEmpty()
-assert mojo.requirements.requirement[1].'field-name'.text() == 'log'
-
-assert mojo.requirements.requirement[2].role.text() == 'org.apache.maven.api.MojoExecution'
-assert mojo.requirements.requirement[2].'role-hint'.isEmpty()
-assert mojo.requirements.requirement[2].'field-name'.text() == 'mojo'
-
-assert mojo.requirements.requirement[3].role.text() == 'org.apache.maven.api.Project'
-assert mojo.requirements.requirement[3].'role-hint'.isEmpty()
-assert mojo.requirements.requirement[3].'field-name'.text() == 'project'
-
-assert mojo.requirements.requirement[4].role.text() == 'org.apache.maven.api.Session'
-assert mojo.requirements.requirement[4].'role-hint'.isEmpty()
-assert mojo.requirements.requirement[4].'field-name'.text() == 'session'
-
-assert mojo.requirements.requirement[5].role.text() == 'org.apache.maven.api.settings.Settings'
-assert mojo.requirements.requirement[5].'role-hint'.isEmpty()
-assert mojo.requirements.requirement[5].'field-name'.text() == 'settings'
assert mojo.parameters.parameter.size() == 3
@@ -90,6 +51,8 @@ assert parameter.deprecated.isEmpty()
assert parameter.required.text() == 'false'
assert parameter.editable.text() == 'false'
assert parameter.description.text() == 'Project directory.'
+assert parameter.defaultValue.text() == '${basedir}'
+assert parameter.expression.isEmpty()
parameter = mojo.parameters.parameter.findAll{ it.name.text() == "touchFile" }[0]
assert parameter.name.text() == 'touchFile'
@@ -100,6 +63,8 @@ assert parameter.deprecated.isEmpty()
assert parameter.required.text() == 'true'
assert parameter.editable.text() == 'true'
assert parameter.description.text() == ''
+assert parameter.defaultValue.text() == '${project.build.directory}/touch.txt'
+assert parameter.expression.text() == '${first.touchFile}'
parameter = mojo.parameters.parameter.findAll{ it.name.text() == "namedParam" }[0]
assert parameter.name.text() == 'namedParam'
@@ -110,6 +75,8 @@ assert parameter.deprecated.text() == 'As of 0.2'
assert parameter.required.text() == 'false'
assert parameter.editable.text() == 'true'
assert parameter.description.text() == ''
+assert parameter.defaultValue.isEmpty()
+assert parameter.expression.isEmpty()
// check help mojo source and class
assert new File( basedir, "target/classes/org/apache/maven/its/v4api/HelpMojo.class" ).isFile()
diff --git a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java
index 862edeaec..73a0e5613 100644
--- a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java
+++ b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/DescriptorGeneratorMojo.java
@@ -19,12 +19,16 @@
package org.apache.maven.plugin.plugin;
import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.net.URI;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
@@ -32,6 +36,7 @@
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
@@ -39,6 +44,7 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
+import org.apache.maven.tools.plugin.ExtendedMojoDescriptor;
import org.apache.maven.tools.plugin.ExtendedPluginDescriptor;
import org.apache.maven.tools.plugin.PluginToolsRequest;
import org.apache.maven.tools.plugin.extractor.ExtractionException;
@@ -48,8 +54,14 @@
import org.apache.maven.tools.plugin.scanner.MojoScanner;
import org.codehaus.plexus.component.repository.ComponentDependency;
import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.io.CachingOutputStream;
+import org.codehaus.plexus.util.io.CachingWriter;
+import org.objectweb.asm.*;
import org.sonatype.plexus.build.incremental.BuildContext;
+import static org.objectweb.asm.Opcodes.*;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+
/**
*
* Generate a plugin descriptor.
@@ -78,6 +90,12 @@ public class DescriptorGeneratorMojo extends AbstractGeneratorMojo {
@Parameter(defaultValue = "${project.build.outputDirectory}/META-INF/maven", readonly = true)
private File outputDirectory;
+ /**
+ * The directory where the generated class files will be put.
+ */
+ @Parameter(defaultValue = "${project.build.outputDirectory}", readonly = true)
+ private File classesOutputDirectory;
+
/**
* The file encoding of the source files.
*
@@ -269,7 +287,6 @@ public class DescriptorGeneratorMojo extends AbstractGeneratorMojo {
protected BuildContext buildContext;
public void generate() throws MojoExecutionException {
-
if (!"maven-plugin".equalsIgnoreCase(project.getArtifactId())
&& project.getArtifactId().toLowerCase().startsWith("maven-")
&& project.getArtifactId().toLowerCase().endsWith("-plugin")
@@ -352,6 +369,12 @@ public void generate() throws MojoExecutionException {
PluginDescriptorFilesGenerator pluginDescriptorGenerator = new PluginDescriptorFilesGenerator();
pluginDescriptorGenerator.execute(outputDirectory, request);
+ // Generate the additional factories for v4 mojos
+ generateFactories(request.getPluginDescriptor());
+
+ // Generate index for v4 beans
+ generateIndex();
+
buildContext.refresh(outputDirectory);
} catch (GeneratorException e) {
throw new MojoExecutionException("Error writing plugin descriptor", e);
@@ -367,6 +390,128 @@ public void generate() throws MojoExecutionException {
}
}
+ private void generateIndex() throws GeneratorException {
+ try {
+ Set diBeans = new TreeSet<>();
+ try (Stream paths = Files.walk(classesOutputDirectory.toPath())) {
+ List classes = paths.filter(
+ p -> p.getFileName().toString().endsWith(".class"))
+ .collect(Collectors.toList());
+ for (Path classFile : classes) {
+ String fileString = classFile.toString();
+ String className = fileString
+ .substring(0, fileString.length() - ".class".length())
+ .replace('/', '.');
+ try (InputStream is = Files.newInputStream(classFile)) {
+ ClassReader rdr = new ClassReader(is);
+ rdr.accept(
+ new ClassVisitor(Opcodes.ASM9) {
+ String className;
+
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ className = name;
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+ if ("Lorg/apache/maven/api/di/Named;".equals(descriptor)) {
+ diBeans.add(className.replace('/', '.'));
+ }
+ return null;
+ }
+ },
+ ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG);
+ }
+
+ // Class> clazz = project.getClassRealm().loadClass(className);
+ // boolean hasQualifier = Stream.of(clazz.getAnnotations())
+ // .flatMap(ann -> Stream.of(ann.getClass().getAnnotations()))
+ // .anyMatch(ann -> "org.apache.maven.api.di.Qualifier"
+ // .equals(ann.annotationType().getName()));
+ // if (hasQualifier) {
+ // diBeans.add(className);
+ // }
+ }
+ }
+ Path path = outputDirectory.toPath().resolve("org.apache.maven.api.di.Inject");
+ if (diBeans.isEmpty()) {
+ Files.deleteIfExists(path);
+ } else {
+ String nl = System.lineSeparator();
+ try (CachingWriter w = new CachingWriter(path, StandardCharsets.UTF_8)) {
+ String content = diBeans.stream().collect(Collectors.joining(nl, "", nl));
+ w.write(content);
+ }
+ }
+ } catch (Exception e) {
+ throw new GeneratorException("Unable to generate index for v4 beans", e);
+ }
+ }
+
+ private void generateFactories(PluginDescriptor pd) throws GeneratorException {
+ try {
+ for (MojoDescriptor md : pd.getMojos()) {
+ if (md instanceof ExtendedMojoDescriptor && ((ExtendedMojoDescriptor) md).isV4Api()) {
+ generateFactory(md);
+ }
+ }
+ } catch (IOException e) {
+ throw new GeneratorException("Unable to generate factories for v4 mojos", e);
+ }
+ }
+
+ private void generateFactory(MojoDescriptor md) throws IOException {
+ String mojoClassName = md.getImplementation();
+ String packageName = mojoClassName.substring(0, mojoClassName.lastIndexOf('.'));
+ String generatorClassName = mojoClassName.substring(mojoClassName.lastIndexOf('.') + 1) + "Factory";
+ String mojoName = md.getId();
+
+ getLog().debug("Generating v4 factory for " + mojoClassName);
+
+ byte[] bin = computeGeneratorClassBytes(packageName, generatorClassName, mojoName, mojoClassName);
+
+ try (OutputStream os = new CachingOutputStream(classesOutputDirectory
+ .toPath()
+ .resolve(packageName.replace('.', '/') + "/" + generatorClassName + ".class"))) {
+ os.write(bin);
+ }
+ }
+
+ static byte[] computeGeneratorClassBytes(
+ String packageName, String generatorClassName, String mojoName, String mojoClassName) {
+ String mojo = mojoClassName.replace('.', '/');
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+ cw.visitSource(generatorClassName + ".java", null);
+ AnnotationVisitor av = cw.visitAnnotation("Lorg/apache/maven/api/di/Named;", true);
+ av.visit("value", mojoName);
+ av.visitEnd();
+ cw.visitAnnotation("Lorg/apache/maven/api/annotations/Generated;", true).visitEnd();
+ cw.visit(
+ V1_8,
+ ACC_PUBLIC + ACC_SUPER + ACC_SYNTHETIC,
+ packageName.replace(".", "/") + "/" + generatorClassName,
+ null,
+ mojo,
+ null);
+ MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_SYNTHETIC, "", "()V", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitMethodInsn(Opcodes.INVOKESPECIAL, mojo, "", "()V", false);
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(-1, -1);
+ mv.visitEnd();
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
private PluginDescriptor extendPluginDescriptor(PluginToolsRequest request) {
ExtendedPluginDescriptor extendedPluginDescriptor = new ExtendedPluginDescriptor(request.getPluginDescriptor());
extendedPluginDescriptor.setRequiredJavaVersion(getRequiredJavaVersion(request));
diff --git a/maven-plugin-report-plugin/src/it/plugin-report-annotations/pom.xml b/maven-plugin-report-plugin/src/it/plugin-report-annotations/pom.xml
index 1f355686d..3522d6abb 100644
--- a/maven-plugin-report-plugin/src/it/plugin-report-annotations/pom.xml
+++ b/maven-plugin-report-plugin/src/it/plugin-report-annotations/pom.xml
@@ -55,12 +55,6 @@ under the License.
@maven3Version@
provided
-
- org.apache.maven.plugin-tools
- maven-plugin-annotations
- @project.version@
- provided
-
org.apache.maven.reporting
maven-reporting-api
diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
index 5979fe700..6c747f4e6 100644
--- a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
+++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugin/plugin/report/PluginReport.java
@@ -35,13 +35,13 @@
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Execute;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.plugin.descriptor.EnhancedPluginDescriptorBuilder;
+import org.apache.maven.plugins.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/EnhancedPluginDescriptorBuilder.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/EnhancedPluginDescriptorBuilder.java
index 2f29303a6..7c15b1b69 100644
--- a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/EnhancedPluginDescriptorBuilder.java
+++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/EnhancedPluginDescriptorBuilder.java
@@ -30,7 +30,6 @@
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
import org.apache.maven.plugin.plugin.report.PluginReport;
import org.apache.maven.rtinfo.RuntimeInformation;
import org.apache.maven.tools.plugin.EnhancedParameterWrapper;
diff --git a/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/PluginDescriptorBuilder.java b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/PluginDescriptorBuilder.java
new file mode 100644
index 000000000..037fdf6fd
--- /dev/null
+++ b/maven-plugin-report-plugin/src/main/java/org/apache/maven/plugins/plugin/descriptor/PluginDescriptorBuilder.java
@@ -0,0 +1,325 @@
+/*
+ * 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.plugins.plugin.descriptor;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.codehaus.plexus.component.repository.ComponentDependency;
+import org.codehaus.plexus.component.repository.ComponentRequirement;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.codehaus.plexus.configuration.PlexusConfigurationException;
+import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * Build plugin descriptor object from {@code plugin.xml}.
+ *
+ * @author Jason van Zyl
+ */
+public class PluginDescriptorBuilder {
+ public PluginDescriptor build(Reader reader) throws PlexusConfigurationException {
+ return build(reader, null);
+ }
+
+ public PluginDescriptor build(Reader reader, String source) throws PlexusConfigurationException {
+ PlexusConfiguration c = buildConfiguration(reader);
+
+ PluginDescriptor pluginDescriptor = new PluginDescriptor();
+
+ pluginDescriptor.setSource(source);
+ pluginDescriptor.setGroupId(c.getChild("groupId").getValue());
+ pluginDescriptor.setArtifactId(c.getChild("artifactId").getValue());
+ pluginDescriptor.setVersion(c.getChild("version").getValue());
+ pluginDescriptor.setGoalPrefix(c.getChild("goalPrefix").getValue());
+
+ pluginDescriptor.setName(c.getChild("name").getValue());
+ pluginDescriptor.setDescription(c.getChild("description").getValue());
+
+ String isolatedRealm = c.getChild("isolatedRealm").getValue();
+
+ if (isolatedRealm != null) {
+ pluginDescriptor.setIsolatedRealm(Boolean.parseBoolean(isolatedRealm));
+ }
+
+ String inheritedByDefault = c.getChild("inheritedByDefault").getValue();
+
+ if (inheritedByDefault != null) {
+ pluginDescriptor.setInheritedByDefault(Boolean.parseBoolean(inheritedByDefault));
+ }
+
+ // ----------------------------------------------------------------------
+ // Components
+ // ----------------------------------------------------------------------
+
+ PlexusConfiguration[] mojoConfigurations = c.getChild("mojos").getChildren("mojo");
+
+ for (PlexusConfiguration component : mojoConfigurations) {
+ MojoDescriptor mojoDescriptor = buildComponentDescriptor(component, pluginDescriptor);
+
+ pluginDescriptor.addMojo(mojoDescriptor);
+ }
+
+ // ----------------------------------------------------------------------
+ // Dependencies
+ // ----------------------------------------------------------------------
+
+ PlexusConfiguration[] dependencyConfigurations =
+ c.getChild("dependencies").getChildren("dependency");
+
+ List dependencies = new ArrayList<>();
+
+ for (PlexusConfiguration d : dependencyConfigurations) {
+ ComponentDependency cd = new ComponentDependency();
+
+ cd.setArtifactId(d.getChild("artifactId").getValue());
+
+ cd.setGroupId(d.getChild("groupId").getValue());
+
+ cd.setType(d.getChild("type").getValue());
+
+ cd.setVersion(d.getChild("version").getValue());
+
+ dependencies.add(cd);
+ }
+
+ pluginDescriptor.setDependencies(dependencies);
+
+ return pluginDescriptor;
+ }
+
+ @SuppressWarnings("checkstyle:methodlength")
+ public MojoDescriptor buildComponentDescriptor(PlexusConfiguration c, PluginDescriptor pluginDescriptor)
+ throws PlexusConfigurationException {
+ MojoDescriptor mojo = new MojoDescriptor();
+ mojo.setPluginDescriptor(pluginDescriptor);
+
+ mojo.setGoal(c.getChild("goal").getValue());
+
+ mojo.setImplementation(c.getChild("implementation").getValue());
+
+ PlexusConfiguration langConfig = c.getChild("language");
+
+ if (langConfig != null) {
+ mojo.setLanguage(langConfig.getValue());
+ }
+
+ PlexusConfiguration configuratorConfig = c.getChild("configurator");
+
+ if (configuratorConfig != null) {
+ mojo.setComponentConfigurator(configuratorConfig.getValue());
+ }
+
+ PlexusConfiguration composerConfig = c.getChild("composer");
+
+ if (composerConfig != null) {
+ mojo.setComponentComposer(composerConfig.getValue());
+ }
+
+ String since = c.getChild("since").getValue();
+
+ if (since != null) {
+ mojo.setSince(since);
+ }
+
+ PlexusConfiguration deprecated = c.getChild("deprecated", false);
+
+ if (deprecated != null) {
+ mojo.setDeprecated(deprecated.getValue());
+ }
+
+ String phase = c.getChild("phase").getValue();
+
+ if (phase != null) {
+ mojo.setPhase(phase);
+ }
+
+ String executePhase = c.getChild("executePhase").getValue();
+
+ if (executePhase != null) {
+ mojo.setExecutePhase(executePhase);
+ }
+
+ String executeMojo = c.getChild("executeGoal").getValue();
+
+ if (executeMojo != null) {
+ mojo.setExecuteGoal(executeMojo);
+ }
+
+ String executeLifecycle = c.getChild("executeLifecycle").getValue();
+
+ if (executeLifecycle != null) {
+ mojo.setExecuteLifecycle(executeLifecycle);
+ }
+
+ mojo.setInstantiationStrategy(c.getChild("instantiationStrategy").getValue());
+
+ mojo.setDescription(c.getChild("description").getValue());
+
+ PlexusConfiguration dependencyResolution = c.getChild("requiresDependencyResolution", false);
+
+ if (dependencyResolution != null) {
+ mojo.setDependencyResolutionRequired(dependencyResolution.getValue());
+ }
+
+ PlexusConfiguration dependencyCollection = c.getChild("requiresDependencyCollection", false);
+
+ if (dependencyCollection != null) {
+ mojo.setDependencyCollectionRequired(dependencyCollection.getValue());
+ }
+
+ String directInvocationOnly = c.getChild("requiresDirectInvocation").getValue();
+
+ if (directInvocationOnly != null) {
+ mojo.setDirectInvocationOnly(Boolean.parseBoolean(directInvocationOnly));
+ }
+
+ String requiresProject = c.getChild("requiresProject").getValue();
+
+ if (requiresProject != null) {
+ mojo.setProjectRequired(Boolean.parseBoolean(requiresProject));
+ }
+
+ String requiresReports = c.getChild("requiresReports").getValue();
+
+ if (requiresReports != null) {
+ mojo.setRequiresReports(Boolean.parseBoolean(requiresReports));
+ }
+
+ String aggregator = c.getChild("aggregator").getValue();
+
+ if (aggregator != null) {
+ mojo.setAggregator(Boolean.parseBoolean(aggregator));
+ }
+
+ String requiresOnline = c.getChild("requiresOnline").getValue();
+
+ if (requiresOnline != null) {
+ mojo.setOnlineRequired(Boolean.parseBoolean(requiresOnline));
+ }
+
+ String inheritedByDefault = c.getChild("inheritedByDefault").getValue();
+
+ if (inheritedByDefault != null) {
+ mojo.setInheritedByDefault(Boolean.parseBoolean(inheritedByDefault));
+ }
+
+ String threadSafe = c.getChild("threadSafe").getValue();
+
+ if (threadSafe != null) {
+ mojo.setThreadSafe(Boolean.parseBoolean(threadSafe));
+ }
+
+ // ----------------------------------------------------------------------
+ // Configuration
+ // ----------------------------------------------------------------------
+
+ PlexusConfiguration mojoConfig = c.getChild("configuration");
+ mojo.setMojoConfiguration(mojoConfig);
+
+ // ----------------------------------------------------------------------
+ // Parameters
+ // ----------------------------------------------------------------------
+
+ PlexusConfiguration[] parameterConfigurations = c.getChild("parameters").getChildren("parameter");
+
+ List parameters = new ArrayList<>();
+
+ for (PlexusConfiguration d : parameterConfigurations) {
+ Parameter parameter = new Parameter();
+
+ parameter.setName(d.getChild("name").getValue());
+
+ parameter.setAlias(d.getChild("alias").getValue());
+
+ parameter.setType(d.getChild("type").getValue());
+
+ String required = d.getChild("required").getValue();
+
+ parameter.setRequired(Boolean.parseBoolean(required));
+
+ PlexusConfiguration editableConfig = d.getChild("editable");
+
+ // we need the null check for pre-build legacy plugins...
+ if (editableConfig != null) {
+ String editable = d.getChild("editable").getValue();
+
+ parameter.setEditable(editable == null || Boolean.parseBoolean(editable));
+ }
+
+ parameter.setDescription(d.getChild("description").getValue());
+
+ parameter.setDeprecated(d.getChild("deprecated").getValue());
+
+ parameter.setImplementation(d.getChild("implementation").getValue());
+
+ parameter.setSince(d.getChild("since").getValue());
+
+ PlexusConfiguration paramConfig = mojoConfig.getChild(parameter.getName(), false);
+ if (paramConfig != null) {
+ parameter.setExpression(paramConfig.getValue(null));
+ parameter.setDefaultValue(paramConfig.getAttribute("default-value"));
+ }
+
+ parameters.add(parameter);
+ }
+
+ mojo.setParameters(parameters);
+
+ // TODO this should not need to be handed off...
+
+ // ----------------------------------------------------------------------
+ // Requirements
+ // ----------------------------------------------------------------------
+
+ PlexusConfiguration[] requirements = c.getChild("requirements").getChildren("requirement");
+
+ for (PlexusConfiguration requirement : requirements) {
+ ComponentRequirement cr = new ComponentRequirement();
+
+ cr.setRole(requirement.getChild("role").getValue());
+
+ cr.setRoleHint(requirement.getChild("role-hint").getValue());
+
+ cr.setFieldName(requirement.getChild("field-name").getValue());
+
+ mojo.addRequirement(cr);
+ }
+
+ return mojo;
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ public PlexusConfiguration buildConfiguration(Reader configuration) throws PlexusConfigurationException {
+ try {
+ return new XmlPlexusConfiguration(Xpp3DomBuilder.build(configuration));
+ } catch (IOException | XmlPullParserException e) {
+ throw new PlexusConfigurationException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/maven-plugin-tools-annotations/pom.xml b/maven-plugin-tools-annotations/pom.xml
index 732fdbe67..bff4e9268 100644
--- a/maven-plugin-tools-annotations/pom.xml
+++ b/maven-plugin-tools-annotations/pom.xml
@@ -36,10 +36,6 @@
org.apache.maven
maven-plugin-api
-
- org.apache.maven
- maven-core
-
org.apache.maven
maven-model
diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ExecuteAnnotationContent.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ExecuteAnnotationContent.java
index c1e3c9302..a8e7af4e5 100644
--- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ExecuteAnnotationContent.java
+++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ExecuteAnnotationContent.java
@@ -19,6 +19,7 @@
package org.apache.maven.tools.plugin.extractor.annotations.datamodel;
import java.lang.annotation.Annotation;
+import java.util.Objects;
import org.apache.maven.plugins.annotations.Execute;
import org.apache.maven.plugins.annotations.LifecyclePhase;
@@ -57,6 +58,20 @@ public String lifecycle() {
}
public void phase(String phase) {
+ if (phase != null && !phase.isEmpty()) {
+ for (LifecyclePhase p : LifecyclePhase.values()) {
+ if (Objects.equals(phase, p.id()) || Objects.equals(phase, p.name())) {
+ this.phase = p;
+ this.customPhase = null;
+ return;
+ }
+ }
+ this.phase = null;
+ this.customPhase = phase;
+ } else {
+ this.phase = null;
+ this.customPhase = null;
+ }
this.phase = LifecyclePhase.valueOf(phase);
}
diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/MojoAnnotationContent.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/MojoAnnotationContent.java
index a3b6f6e80..121969905 100644
--- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/MojoAnnotationContent.java
+++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/MojoAnnotationContent.java
@@ -19,6 +19,7 @@
package org.apache.maven.tools.plugin.extractor.annotations.datamodel;
import java.lang.annotation.Annotation;
+import java.util.Objects;
import org.apache.maven.plugins.annotations.InstantiationStrategy;
import org.apache.maven.plugins.annotations.LifecyclePhase;
@@ -69,7 +70,17 @@ public LifecyclePhase defaultPhase() {
}
public void defaultPhase(String phase) {
- this.defaultPhase = LifecyclePhase.valueOf(phase);
+ if (phase != null && !phase.isEmpty()) {
+ for (LifecyclePhase p : LifecyclePhase.values()) {
+ if (Objects.equals(phase, p.id()) || Objects.equals(phase, p.name())) {
+ this.defaultPhase = p;
+ return;
+ }
+ }
+ throw new IllegalArgumentException("Could not find a matching phase for " + phase);
+ } else {
+ this.defaultPhase = null;
+ }
}
@Override
@@ -81,6 +92,10 @@ public void requiresDependencyResolution(String requiresDependencyResolution) {
this.requiresDependencyResolution = ResolutionScope.valueOf(requiresDependencyResolution);
}
+ public void dependencyResolutionRequired(String dependencyResolutionRequired) {
+ this.requiresDependencyResolution = ResolutionScope.valueOf(dependencyResolutionRequired);
+ }
+
@Override
public ResolutionScope requiresDependencyCollection() {
return requiresDependencyCollection;
@@ -117,6 +132,10 @@ public void requiresProject(boolean requiresProject) {
this.requiresProject = requiresProject;
}
+ public void projectRequired(boolean requiresProject) {
+ this.requiresProject = requiresProject;
+ }
+
@Override
public boolean requiresReports() {
return requiresReports;
diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScanner.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScanner.java
index a91aea24e..759890115 100644
--- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScanner.java
+++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScanner.java
@@ -31,6 +31,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -70,7 +71,6 @@ public class DefaultMojoAnnotationsScanner extends AbstractLogEnabled implements
public static final String MOJO_V4 = MVN4_API + "Mojo";
public static final String EXECUTE_V4 = MVN4_API + "Execute";
public static final String PARAMETER_V4 = MVN4_API + "Parameter";
- public static final String COMPONENT_V4 = MVN4_API + "Component";
public static final String MOJO_V3 = Mojo.class.getName();
public static final String EXECUTE_V3 = Execute.class.getName();
@@ -88,15 +88,23 @@ public Map scan(MojoAnnotationsScannerRequest reques
Map mojoAnnotatedClasses = new HashMap<>();
try {
+ String mavenApiVersion = null;
for (Artifact dependency : request.getDependencies()) {
scan(mojoAnnotatedClasses, dependency.getFile(), request.getIncludePatterns(), dependency, true);
if (request.getMavenApiVersion() == null
&& dependency.getGroupId().equals("org.apache.maven")
&& (dependency.getArtifactId().equals("maven-plugin-api")
|| dependency.getArtifactId().equals("maven-api-core"))) {
- request.setMavenApiVersion(dependency.getVersion());
+ String version = dependency.getVersion();
+ if (mavenApiVersion != null && !Objects.equals(version, mavenApiVersion)) {
+ throw new UnsupportedOperationException("Mixing Maven 3 and Maven 4 plugins is not supported."
+ + " Fix your dependencies so that you depend either on maven-plugin-api for a Maven 3 plugin,"
+ + " or maven-api-core for a Maven 4 plugin.");
+ }
+ mavenApiVersion = version;
}
}
+ request.setMavenApiVersion(mavenApiVersion);
for (File classDirectory : request.getClassesDirectories()) {
scan(
@@ -332,16 +340,13 @@ protected void analyzeVisitors(MojoClassVisitor mojoClassVisitor) throws Extract
// @Component annotations
List mojoFieldVisitors =
- mojoClassVisitor.findFieldWithAnnotation(new HashSet<>(Arrays.asList(COMPONENT_V3, COMPONENT_V4)));
+ mojoClassVisitor.findFieldWithAnnotation(new HashSet<>(Arrays.asList(COMPONENT_V3)));
for (MojoFieldVisitor mojoFieldVisitor : mojoFieldVisitors) {
ComponentAnnotationContent componentAnnotationContent =
new ComponentAnnotationContent(mojoFieldVisitor.getFieldName());
Map annotationVisitorMap = mojoFieldVisitor.getAnnotationVisitorMap();
MojoAnnotationVisitor annotationVisitor = annotationVisitorMap.get(COMPONENT_V3);
- if (annotationVisitor == null) {
- annotationVisitor = annotationVisitorMap.get(COMPONENT_V4);
- }
if (annotationVisitor != null) {
for (Map.Entry entry :
diff --git a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java
index d5796ba5b..5de14478e 100644
--- a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java
+++ b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java
@@ -46,6 +46,9 @@ public class ParametersWithGenericsMojo extends AbstractMojo {
@Parameter
private Collection integerArrayCollection;
+ @Parameter
+ private Map> stringListStringMap;
+
@Override
public void execute() throws MojoExecutionException, MojoFailureException {}
diff --git a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java
index 83dd04c47..bc8c0723b 100644
--- a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java
+++ b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java
@@ -132,6 +132,12 @@ void scanParametersWithGenerics() throws ExtractionException, IOException {
assertNotNull(parameter);
assertEquals("java.util.List", parameter.getClassName());
assertThat(parameter.getTypeParameters()).containsExactly("java.lang.Number");
+
+ parameter = annotatedClass.getParameters().get("stringListStringMap");
+ assertNotNull(parameter);
+ assertEquals("java.util.Map", parameter.getClassName());
+ assertThat(parameter.getTypeParameters())
+ .containsExactly("java.lang.String", "java.util.List");
}
@Test
diff --git a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedPluginDescriptor.java b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedPluginDescriptor.java
index bb3dc5c04..0ae9e9352 100644
--- a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedPluginDescriptor.java
+++ b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedPluginDescriptor.java
@@ -18,7 +18,6 @@
*/
package org.apache.maven.tools.plugin;
-import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -29,9 +28,7 @@
import org.apache.maven.plugin.descriptor.DuplicateMojoDescriptorException;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.lifecycle.Lifecycle;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
/**
* Extensions to {@link PluginDescriptor} not supported by Maven 3.2.5.
@@ -91,6 +88,12 @@ public void addMojo(MojoDescriptor mojoDescriptor) throws DuplicateMojoDescripto
delegate.addMojo(mojoDescriptor);
}
+ public void addMojos(List mojos) throws DuplicateMojoDescriptorException {
+ for (MojoDescriptor mojoDescriptor : mojos) {
+ addMojo(mojoDescriptor);
+ }
+ }
+
public String getGroupId() {
return delegate.getGroupId();
}
@@ -222,11 +225,6 @@ public void setPluginArtifact(Artifact pluginArtifact) {
delegate.setPluginArtifact(pluginArtifact);
}
- @Override
- public Lifecycle getLifecycleMapping(String lifecycleId) throws IOException, XmlPullParserException {
- return delegate.getLifecycleMapping(lifecycleId);
- }
-
public PluginDescriptor clone() {
return delegate.clone();
}
diff --git a/maven-plugin-tools-generators/pom.xml b/maven-plugin-tools-generators/pom.xml
index b2af7953b..dd1aabe94 100644
--- a/maven-plugin-tools-generators/pom.xml
+++ b/maven-plugin-tools-generators/pom.xml
@@ -54,6 +54,8 @@
org.apache.maven
maven-plugin-api
+ ${maven3Version}
+ provided
org.apache.maven
@@ -89,6 +91,15 @@
${slf4jVersion}
+
+ org.ow2.asm
+ asm
+
+
+ org.ow2.asm
+ asm-commons
+
+
org.jsoup
@@ -108,6 +119,11 @@
junit-jupiter-engine
test
+
+ org.apache.maven.resolver
+ maven-resolver-impl
+ ${resolverVersion}
+
org.codehaus.plexus
plexus-testing
diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGenerator.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGenerator.java
index c6923de67..ac83bc42e 100644
--- a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGenerator.java
+++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGenerator.java
@@ -110,6 +110,9 @@ public void writeDescriptor(File destinationFile, PluginToolsRequest request, De
destinationFile.getParentFile().mkdirs();
}
+ String apiVersion = request.getPluginDescriptor().getRequiredMavenVersion();
+ boolean isV4 = apiVersion != null && apiVersion.startsWith("4.");
+
try (Writer writer = new OutputStreamWriter(new CachingOutputStream(destinationFile), UTF_8)) {
XMLWriter w = new PrettyPrintXMLWriter(writer, UTF_8.name(), null);
@@ -128,6 +131,13 @@ public void writeDescriptor(File destinationFile, PluginToolsRequest request, De
w.writeMarkup("\n\n\n");
w.startElement("plugin");
+ if (isV4) {
+ w.addAttribute("xmlns", "http://maven.apache.org/PLUGIN/2.0.0");
+ w.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
+ w.addAttribute(
+ "xsi:location",
+ "http://maven.apache.org/PLUGIN/2.0.0 https://maven.apache.org/xsd/plugin-2.0.0.xsd");
+ }
GeneratorUtils.element(w, "name", pluginDescriptor.getName());
@@ -178,13 +188,13 @@ public void writeDescriptor(File destinationFile, PluginToolsRequest request, De
PluginUtils.sortMojos(descriptors);
for (MojoDescriptor descriptor : descriptors) {
- processMojoDescriptor(descriptor, w, type, javadocLinkGenerator);
+ processMojoDescriptor(descriptor, w, type, javadocLinkGenerator, isV4);
}
}
w.endElement();
- if (type != DescriptorType.LIMITED_FOR_HELP_MOJO) {
+ if (!isV4 && type != DescriptorType.LIMITED_FOR_HELP_MOJO) {
GeneratorUtils.writeDependencies(w, pluginDescriptor);
}
@@ -221,7 +231,8 @@ protected void processMojoDescriptor(
MojoDescriptor mojoDescriptor,
XMLWriter w,
DescriptorType type,
- JavadocLinkGenerator javadocLinkGenerator) {
+ JavadocLinkGenerator javadocLinkGenerator,
+ boolean isV4) {
boolean containsXhtmlTextValues = mojoDescriptor instanceof ExtendedMojoDescriptor
&& ((ExtendedMojoDescriptor) mojoDescriptor).containsXhtmlTextValues();
@@ -251,27 +262,36 @@ protected void processMojoDescriptor(
//
// ----------------------------------------------------------------------
- if (StringUtils.isNotEmpty(mojoDescriptor.isDependencyResolutionRequired())) {
- GeneratorUtils.element(w, "requiresDependencyResolution", mojoDescriptor.isDependencyResolutionRequired());
+ if (StringUtils.isNotEmpty(mojoDescriptor.getDependencyResolutionRequired())) {
+ GeneratorUtils.element(
+ w,
+ isV4 ? "dependencyResolution" : "requiresDependencyResolution",
+ mojoDescriptor.getDependencyResolutionRequired());
}
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
- GeneratorUtils.element(w, "requiresDirectInvocation", String.valueOf(mojoDescriptor.isDirectInvocationOnly()));
+ GeneratorUtils.element(
+ w,
+ isV4 ? "directInvocationOnly" : "requiresDirectInvocation",
+ String.valueOf(mojoDescriptor.isDirectInvocationOnly()));
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
- GeneratorUtils.element(w, "requiresProject", String.valueOf(mojoDescriptor.isProjectRequired()));
+ GeneratorUtils.element(
+ w, isV4 ? "projectRequired" : "requiresProject", String.valueOf(mojoDescriptor.isProjectRequired()));
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
- GeneratorUtils.element(w, "requiresReports", String.valueOf(mojoDescriptor.isRequiresReports()));
+ if (!isV4) {
+ GeneratorUtils.element(w, "requiresReports", String.valueOf(mojoDescriptor.isRequiresReports()));
+ }
// ----------------------------------------------------------------------
//
@@ -283,7 +303,8 @@ protected void processMojoDescriptor(
//
// ----------------------------------------------------------------------
- GeneratorUtils.element(w, "requiresOnline", String.valueOf(mojoDescriptor.isOnlineRequired()));
+ GeneratorUtils.element(
+ w, isV4 ? "onlineRequired" : "requiresOnline", String.valueOf(mojoDescriptor.isOnlineRequired()));
// ----------------------------------------------------------------------
//
@@ -345,7 +366,7 @@ protected void processMojoDescriptor(
//
// ----------------------------------------------------------------------
- if (StringUtils.isNotEmpty(mojoDescriptor.getComponentComposer())) {
+ if (!isV4 && StringUtils.isNotEmpty(mojoDescriptor.getComponentComposer())) {
w.startElement("composer");
w.writeText(mojoDescriptor.getComponentComposer());
w.endElement();
@@ -355,17 +376,22 @@ protected void processMojoDescriptor(
//
// ----------------------------------------------------------------------
- w.startElement("instantiationStrategy");
- w.writeText(mojoDescriptor.getInstantiationStrategy());
- w.endElement();
+ if (!isV4) {
+ w.startElement("instantiationStrategy");
+ w.writeText(mojoDescriptor.getInstantiationStrategy());
+ w.endElement();
+ }
// ----------------------------------------------------------------------
// Strategy for handling repeated reference to mojo in
// the calculated (decorated, resolved) execution stack
// ----------------------------------------------------------------------
- w.startElement("executionStrategy");
- w.writeText(mojoDescriptor.getExecutionStrategy());
- w.endElement();
+
+ if (!isV4) {
+ w.startElement("executionStrategy");
+ w.writeText(mojoDescriptor.getExecutionStrategy());
+ w.endElement();
+ }
// ----------------------------------------------------------------------
//
@@ -407,14 +433,12 @@ protected void processMojoDescriptor(
ExtendedMojoDescriptor extendedMojoDescriptor = (ExtendedMojoDescriptor) mojoDescriptor;
if (extendedMojoDescriptor.getDependencyCollectionRequired() != null) {
GeneratorUtils.element(
- w, "requiresDependencyCollection", extendedMojoDescriptor.getDependencyCollectionRequired());
+ w,
+ isV4 ? "dependencyCollection" : "requiresDependencyCollection",
+ extendedMojoDescriptor.getDependencyCollectionRequired());
}
-
- GeneratorUtils.element(w, "threadSafe", String.valueOf(extendedMojoDescriptor.isThreadSafe()));
-
- boolean v4Api = extendedMojoDescriptor.isV4Api();
- if (v4Api) {
- GeneratorUtils.element(w, "v4Api", String.valueOf(v4Api));
+ if (!isV4) {
+ GeneratorUtils.element(w, "threadSafe", String.valueOf(extendedMojoDescriptor.isThreadSafe()));
}
}
@@ -495,7 +519,7 @@ else if (type != DescriptorType.LIMITED_FOR_HELP_MOJO || parameter.isEditable())
}
}
- if (parameter.getImplementation() != null) {
+ if (!isV4 && parameter.getImplementation() != null) {
GeneratorUtils.element(w, "implementation", parameter.getImplementation());
}
@@ -506,9 +530,18 @@ else if (type != DescriptorType.LIMITED_FOR_HELP_MOJO || parameter.isEditable())
GeneratorUtils.element(
w, "description", getTextValue(type, containsXhtmlTextValues, parameter.getDescription()));
- if (StringUtils.isNotEmpty(parameter.getDefaultValue())
- || StringUtils.isNotEmpty(parameter.getExpression())) {
- configuration.add(parameter);
+ if (isV4) {
+ if (StringUtils.isNotEmpty(parameter.getExpression())) {
+ GeneratorUtils.element(w, "expression", parameter.getExpression());
+ }
+ if (StringUtils.isNotEmpty(parameter.getDefaultValue())) {
+ GeneratorUtils.element(w, "defaultValue", parameter.getDefaultValue());
+ }
+ } else {
+ if (StringUtils.isNotEmpty(parameter.getDefaultValue())
+ || StringUtils.isNotEmpty(parameter.getExpression())) {
+ configuration.add(parameter);
+ }
}
w.endElement();
diff --git a/maven-plugin-tools-generators/src/main/resources/help-class-source-v4.vm b/maven-plugin-tools-generators/src/main/resources/help-class-source-v4.vm
index 0ac5b891a..008c52192 100644
--- a/maven-plugin-tools-generators/src/main/resources/help-class-source-v4.vm
+++ b/maven-plugin-tools-generators/src/main/resources/help-class-source-v4.vm
@@ -18,8 +18,8 @@
package ${helpPackageName};
#end
+import org.apache.maven.api.di.Inject;
import org.apache.maven.api.plugin.MojoException;
-import org.apache.maven.api.plugin.annotations.Component;
import org.apache.maven.api.plugin.annotations.Mojo;
import org.apache.maven.api.plugin.annotations.Parameter;
import org.apache.maven.api.plugin.Log;
@@ -43,11 +43,11 @@ import java.util.List;
* Call mvn ${goalPrefix}:help -Ddetail=true -Dgoal=<goal-name> to display parameter details.
* @author maven-plugin-tools
*/
-@Mojo( name = "help", requiresProject = false )
+@Mojo( name = "help", projectRequired = false )
public class HelpMojo
implements org.apache.maven.api.plugin.Mojo
{
- @Component
+ @Inject
private Log logger;
/**
@@ -189,6 +189,21 @@ public class HelpMojo
return getSingleChild( node, elementName ).getTextContent();
}
+ private static String getValueOr( Node node, String elementName, String def )
+ throws MojoException
+ {
+ List namedChild = findNamedChild( node, elementName );
+ if ( namedChild.isEmpty() )
+ {
+ return def;
+ }
+ if ( namedChild.size() > 1 )
+ {
+ throw new MojoException( "Multiple " + elementName + " in plugin-help.xml" );
+ }
+ return namedChild.get( 0 ).getTextContent();
+ }
+
private static Node getSingleChild( Node node, String elementName )
throws MojoException
{
@@ -286,10 +301,10 @@ public class HelpMojo
fieldConfigurationElement = (Element) findSingleChild( configurationElement, parameterName );
}
- String parameterDefaultValue = "";
- if ( fieldConfigurationElement != null && fieldConfigurationElement.hasAttribute( "default-value" ) )
+ String parameterDefaultValue = getValueOr( parameter, "defaultValue", "" );
+ if ( isNotEmpty( parameterDefaultValue ) )
{
- parameterDefaultValue = " (Default: " + fieldConfigurationElement.getAttribute( "default-value" ) + ")";
+ parameterDefaultValue = " (Default: " + parameterDefaultValue + ")";
}
append( sb, parameterName + parameterDefaultValue, 2 );
Node deprecated = findSingleChild( parameter, "deprecated" );
@@ -305,9 +320,11 @@ public class HelpMojo
{
append( sb, "Required: Yes", 3 );
}
- if ( ( fieldConfigurationElement != null ) && isNotEmpty( fieldConfigurationElement.getTextContent() ) )
+
+ String parameterExpression = getValueOr( parameter, "expression", "" );
+ if ( isNotEmpty( parameterExpression ) )
{
- String property = getPropertyFromExpression( fieldConfigurationElement.getTextContent() );
+ String property = getPropertyFromExpression( parameterExpression );
append( sb, "User property: " + property, 3 );
}
diff --git a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/AbstractGeneratorTestCase.java b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/AbstractGeneratorTestCase.java
index f592b6319..4b63712f7 100644
--- a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/AbstractGeneratorTestCase.java
+++ b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/AbstractGeneratorTestCase.java
@@ -36,6 +36,7 @@
import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
import org.codehaus.plexus.component.repository.ComponentDependency;
import org.codehaus.plexus.util.FileUtils;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
/**
@@ -105,7 +106,74 @@ public void testGenerator() throws Exception {
extendPluginDescriptor(pluginDescriptor);
generator.execute(destinationDirectory, new DefaultPluginToolsRequest(mavenProject, pluginDescriptor));
- validate(destinationDirectory);
+ validate(destinationDirectory, false);
+
+ FileUtils.deleteDirectory(destinationDirectory);
+ }
+
+ @Test
+ @Disabled
+ public void testGeneratorV4() throws Exception {
+ setupGenerator();
+
+ MojoDescriptor mojoDescriptor = new MojoDescriptor();
+ mojoDescriptor.setGoal("testGoal");
+ mojoDescriptor.setImplementation("org.apache.maven.tools.plugin.generator.TestMojo");
+ mojoDescriptor.setDependencyResolutionRequired("compile");
+ mojoDescriptor.setSince("mojoSince");
+
+ List params = new ArrayList<>();
+
+ Parameter param = new Parameter();
+ param.setExpression("${project.build.directory}");
+ param.setDefaultValue("");
+ param.setName("dir");
+ param.setRequired(true);
+ param.setType("java.lang.String");
+ param.setDescription("Test parameter description");
+ param.setAlias("some.alias");
+ param.setSince("paramDirSince");
+ params.add(param);
+
+ param = new Parameter();
+ param.setName("withoutSince");
+ param.setType("java.lang.String");
+ params.add(param);
+
+ mojoDescriptor.setParameters(params);
+
+ PluginDescriptor pluginDescriptor = new PluginDescriptor();
+ mojoDescriptor.setPluginDescriptor(pluginDescriptor);
+
+ pluginDescriptor.addMojo(mojoDescriptor);
+
+ pluginDescriptor.setArtifactId("maven-unitTesting-plugin");
+ pluginDescriptor.setGoalPrefix("test");
+
+ ComponentDependency dependency = new ComponentDependency();
+ dependency.setGroupId("testGroup");
+ dependency.setArtifactId("testArtifact");
+ dependency.setVersion("0.0.0");
+
+ pluginDescriptor.setDependencies(Collections.singletonList(dependency));
+
+ File destinationDirectory =
+ Files.createTempDirectory("testGenerator-outDir").toFile();
+ destinationDirectory.mkdir();
+
+ MavenProject mavenProject = new MavenProject();
+ mavenProject.setGroupId("foo");
+ mavenProject.setArtifactId("bar");
+ Build build = new Build();
+ build.setDirectory(basedir + "/target");
+ build.setOutputDirectory(basedir + "/target");
+ mavenProject.setBuild(build);
+ extendPluginDescriptor(pluginDescriptor);
+ DefaultPluginToolsRequest request = new DefaultPluginToolsRequest(mavenProject, pluginDescriptor);
+ pluginDescriptor.setRequiredMavenVersion("4.0.0");
+ generator.execute(destinationDirectory, request);
+
+ validate(destinationDirectory, true);
FileUtils.deleteDirectory(destinationDirectory);
}
@@ -145,7 +213,7 @@ protected void setupGenerator() throws Exception {
//
// ----------------------------------------------------------------------
- protected void validate(File destinationDirectory) throws Exception {
+ protected void validate(File destinationDirectory, boolean isV4) throws Exception {
// empty
}
}
diff --git a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java
index eb35539e4..98fd2e41e 100644
--- a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java
+++ b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java
@@ -60,35 +60,33 @@ protected void extendPluginDescriptor(PluginDescriptor pluginDescriptor) throws
}
@Override
- protected void validate(File destinationDirectory) throws Exception {
+ protected void validate(File destinationDirectory, boolean isV4) throws Exception {
PluginDescriptorBuilder pdb = new PluginDescriptorBuilder();
File pluginDescriptorFile = new File(destinationDirectory, "plugin.xml");
String pd = readFile(pluginDescriptorFile);
+ System.err.println(pd);
+
PluginDescriptor pluginDescriptor = pdb.build(new StringReader(pd));
assertEquals(1, pluginDescriptor.getMojos().size());
MojoDescriptor mojoDescriptor = pluginDescriptor.getMojos().get(0);
- checkMojo(mojoDescriptor);
+ checkMojo(mojoDescriptor, isV4);
// ----------------------------------------------------------------------
// Dependencies
// ----------------------------------------------------------------------
- List dependencies = pluginDescriptor.getDependencies();
-
- checkDependency("testGroup", "testArtifact", "0.0.0", dependencies.get(0));
+ if (!isV4) {
+ List dependencies = pluginDescriptor.getDependencies();
- assertEquals(1, dependencies.size());
-
- ComponentDependency dependency = dependencies.get(0);
- assertEquals("testGroup", dependency.getGroupId());
- assertEquals("testArtifact", dependency.getArtifactId());
- assertEquals("0.0.0", dependency.getVersion());
+ assertEquals(1, dependencies.size());
+ checkDependency("testGroup", "testArtifact", "0.0.0", dependencies.get(0));
+ }
}
private String readFile(File pluginDescriptorFile) throws IOException {
@@ -105,15 +103,19 @@ private String readFile(File pluginDescriptorFile) throws IOException {
return sWriter.toString();
}
- private void checkMojo(MojoDescriptor mojoDescriptor) {
+ private void checkMojo(MojoDescriptor mojoDescriptor, boolean isV4) {
assertEquals("test:testGoal", mojoDescriptor.getFullGoalName());
assertEquals("org.apache.maven.tools.plugin.generator.TestMojo", mojoDescriptor.getImplementation());
// The following should be defaults
- assertEquals("per-lookup", mojoDescriptor.getInstantiationStrategy());
+ if (!isV4) {
+ assertEquals("per-lookup", mojoDescriptor.getInstantiationStrategy());
+ }
- assertNotNull(mojoDescriptor.isDependencyResolutionRequired());
+ if (!isV4) {
+ assertNotNull(mojoDescriptor.getDependencyResolutionRequired());
+ }
// check the default parameter
checkParameter(mojoDescriptor.getParameters().get(0));
@@ -124,12 +126,17 @@ private void checkMojo(MojoDescriptor mojoDescriptor) {
assertEquals("parameterWithGenerics", parameterWithGenerics.getName());
assertEquals("java.util.Collection", parameterWithGenerics.getType());
- PlexusConfiguration configurations = mojoDescriptor.getMojoConfiguration();
- assertNotNull(configurations);
- PlexusConfiguration configuration = configurations.getChild("parameterWithGenerics");
- assertEquals("java.util.Collection", configuration.getAttribute("implementation"));
- assertEquals("a,b,c", configuration.getAttribute("default-value"));
- assertEquals("${customParam}", configuration.getValue());
+ if (isV4) {
+ assertEquals("${customParam}", parameterWithGenerics.getExpression());
+ assertEquals("a,b,c", parameterWithGenerics.getDefaultValue());
+ } else {
+ PlexusConfiguration configurations = mojoDescriptor.getMojoConfiguration();
+ assertNotNull(configurations);
+ PlexusConfiguration configuration = configurations.getChild("parameterWithGenerics");
+ assertEquals("java.util.Collection", configuration.getAttribute("implementation"));
+ assertEquals("a,b,c", configuration.getAttribute("default-value"));
+ assertEquals("${customParam}", configuration.getValue());
+ }
}
private void checkParameter(Parameter parameter) {
diff --git a/pom.xml b/pom.xml
index a4cfceb67..4def9de6f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,7 +90,7 @@
8
3.3.0
- 4.0.0-alpha-4
+ 4.0.0-beta-3
3.9.6
1.9.18
1.7.36
@@ -308,6 +308,21 @@
+
+ org.apache.maven.plugins
+ maven-enforcer-plugin
+
+
+
+ ${maven.compiler.target}
+
+ org.apache.maven:*
+
+
+
+ true
+
+
org.apache.maven.plugins
maven-javadoc-plugin