You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sj...@apache.org on 2022/07/28 16:25:35 UTC

[maven-plugin-tools] 01/01: [MPLUGIN-408] helpmojo improvement

This is an automated email from the ASF dual-hosted git repository.

sjaranowski pushed a commit to branch MPLUGIN-408
in repository https://gitbox.apache.org/repos/asf/maven-plugin-tools.git

commit 2c996dd55a390579936a24ba92205ecd6f85cf77
Author: Slawomir Jaranowski <s....@gmail.com>
AuthorDate: Thu Jul 28 18:14:48 2022 +0200

    [MPLUGIN-408] helpmojo improvement
    
    - use groupId + artifactId for calculating package name
    - discover mojos only ones by descriptor mojo
    - simplify in AbstractGeneratorMojo
    - remove unneeded code
---
 maven-plugin-plugin/pom.xml                        |   2 +-
 .../verify.groovy                                  |   7 +-
 .../it/annotation-with-inheritance/verify.groovy   |   7 +-
 .../java-basic-annotations-jdk8/invoker.properties |   4 +-
 .../src/it/java-basic-annotations-jdk8/pom.xml     |   2 +-
 .../it/java-basic-annotations-jdk8/verify.groovy   |   5 +-
 .../verify.groovy                                  |   5 +-
 .../src/it/java-basic-annotations/verify.groovy    |  10 +-
 .../it/mplugin-363_help-reproducible/verify.groovy |   4 +-
 .../maven/plugin/plugin/AbstractGeneratorMojo.java | 302 +-----------------
 .../plugin/plugin/DescriptorGeneratorMojo.java     | 288 ++++++++++++++++--
 .../maven/plugin/plugin/HelpGeneratorMojo.java     |  85 ++++--
 .../maven/plugin/plugin/HelpGeneratorMojoTest.java |  63 ++++
 .../generator/PluginDescriptorGenerator.java       |  28 +-
 .../plugin/generator/PluginHelpGenerator.java      | 336 ++-------------------
 .../plugin/generator/PluginHelpGeneratorTest.java  |  46 ---
 .../javadoc/JavaMojoDescriptorExtractorTest.java   |   2 +-
 pom.xml                                            |   9 +-
 18 files changed, 463 insertions(+), 742 deletions(-)

diff --git a/maven-plugin-plugin/pom.xml b/maven-plugin-plugin/pom.xml
index 448f6bd9..5642641e 100644
--- a/maven-plugin-plugin/pom.xml
+++ b/maven-plugin-plugin/pom.xml
@@ -179,7 +179,7 @@
     <!-- tests -->
     <dependency>
       <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-engine</artifactId>
+      <artifactId>junit-jupiter</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/maven-plugin-plugin/src/it/annotation-with-inheritance-from-deps/verify.groovy b/maven-plugin-plugin/src/it/annotation-with-inheritance-from-deps/verify.groovy
index 1ef2944d..b941b803 100644
--- a/maven-plugin-plugin/src/it/annotation-with-inheritance-from-deps/verify.groovy
+++ b/maven-plugin-plugin/src/it/annotation-with-inheritance-from-deps/verify.groovy
@@ -20,11 +20,8 @@
 File descriptorFile = new File( basedir, "target/classes/META-INF/maven/plugin.xml" );
 assert descriptorFile.isFile()
 
-File oldHelpClass = new File( basedir, "target/classes/HelpMojo.class" );
-assert !oldHelpClass.exists()
-
-File newHelpClass = new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" );
-assert newHelpClass.exists()
+File helpClass = new File( basedir, "target/classes/org/apache/maven/its/annotation_with_inheritance_from_deps/annotation_with_inheritance_from_deps/HelpMojo.class" );
+assert helpClass.exists()
 
 def pluginDescriptor = new XmlParser().parse( descriptorFile );
 
diff --git a/maven-plugin-plugin/src/it/annotation-with-inheritance/verify.groovy b/maven-plugin-plugin/src/it/annotation-with-inheritance/verify.groovy
index d066901a..689e0008 100644
--- a/maven-plugin-plugin/src/it/annotation-with-inheritance/verify.groovy
+++ b/maven-plugin-plugin/src/it/annotation-with-inheritance/verify.groovy
@@ -23,11 +23,8 @@ assert touchFile.isFile()
 File descriptorFile = new File( basedir, "target/classes/META-INF/maven/plugin.xml" );
 assert descriptorFile.isFile()
 
-File oldHelpClass = new File( basedir, "target/classes/HelpMojo.class" );
-assert !oldHelpClass.exists()
-
-File newHelpClass = new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" );
-assert newHelpClass.exists()
+File helpClass = new File( basedir, "target/classes/org/apache/maven/its/annotation_with_inheritance/annotation_with_inheritance/HelpMojo.class" );
+assert helpClass.exists()
 
 def pluginDescriptor = new XmlParser().parse( descriptorFile );
 
diff --git a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/invoker.properties b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/invoker.properties
index d0a9e140..6760204d 100644
--- a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/invoker.properties
+++ b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/invoker.properties
@@ -16,5 +16,5 @@
 # under the License.
 
 invoker.goals.1 = clean install
-invoker.goals.2 = org.apache.maven.its.basic-java-annotations:maven-it-basic-java-annotations:1.0-SNAPSHOT:it0014
-invoker.goals.3 = org.apache.maven.its.basic-java-annotations:maven-it-basic-java-annotations:1.0-SNAPSHOT:help
+invoker.goals.2 = org.apache.maven.its.basic-java-annotations:123-maven-it-basic-java-annotations:1.0-SNAPSHOT:it0014
+invoker.goals.3 = org.apache.maven.its.basic-java-annotations:123-maven-it-basic-java-annotations:1.0-SNAPSHOT:help
diff --git a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/pom.xml b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/pom.xml
index 124b37cc..dda14a8a 100644
--- a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/pom.xml
+++ b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/pom.xml
@@ -23,7 +23,7 @@ under the License.
   <modelVersion>4.0.0</modelVersion>
 
   <groupId>org.apache.maven.its.basic-java-annotations</groupId>
-  <artifactId>maven-it-basic-java-annotations</artifactId>
+  <artifactId>123-maven-it-basic-java-annotations</artifactId>
   <version>1.0-SNAPSHOT</version>
   <packaging>maven-plugin</packaging>
 
diff --git a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/verify.groovy b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/verify.groovy
index 294f5386..b130e2c5 100644
--- a/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/verify.groovy
+++ b/maven-plugin-plugin/src/it/java-basic-annotations-jdk8/verify.groovy
@@ -224,8 +224,7 @@ requirement = mojo.requirements.requirement.findAll{ it.'field-name'.text() == "
 assert requirement.role.text() == 'org.apache.maven.project.MavenProjectHelper'
 
 // check help mojo source and class
-assert new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" ).isFile()
-assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/plugin/coreit/HelpMojo.java" ).isFile()
-assert !new File( basedir, "target/generated-sources/plugin/HelpMojo.java" ).isFile()
+assert new File( basedir, "target/classes/org/apache/maven/its/basic_java_annotations/_123_maven_it_basic_java_annotations/HelpMojo.class" ).isFile()
+assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/its/basic_java_annotations/_123_maven_it_basic_java_annotations/HelpMojo.java" ).isFile()
 
 return true;
diff --git a/maven-plugin-plugin/src/it/java-basic-annotations-jdkcurrent/verify.groovy b/maven-plugin-plugin/src/it/java-basic-annotations-jdkcurrent/verify.groovy
index 294f5386..c498a221 100644
--- a/maven-plugin-plugin/src/it/java-basic-annotations-jdkcurrent/verify.groovy
+++ b/maven-plugin-plugin/src/it/java-basic-annotations-jdkcurrent/verify.groovy
@@ -224,8 +224,7 @@ requirement = mojo.requirements.requirement.findAll{ it.'field-name'.text() == "
 assert requirement.role.text() == 'org.apache.maven.project.MavenProjectHelper'
 
 // check help mojo source and class
-assert new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" ).isFile()
-assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/plugin/coreit/HelpMojo.java" ).isFile()
-assert !new File( basedir, "target/generated-sources/plugin/HelpMojo.java" ).isFile()
+assert new File( basedir, "target/classes/org/apache/maven/its/basic_java_annotations/maven_it_basic_java_annotations/HelpMojo.class" ).isFile()
+assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/its/basic_java_annotations/maven_it_basic_java_annotations/HelpMojo.java" ).isFile()
 
 return true;
diff --git a/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy b/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy
index 0541a8f1..4315bef7 100644
--- a/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy
+++ b/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy
@@ -224,9 +224,13 @@ requirement = mojo.requirements.requirement.findAll{ it.'field-name'.text() == "
 assert requirement.role.text() == 'org.apache.maven.project.MavenProjectHelper'
 
 // check help mojo source and class
-assert new File( basedir, "target/classes/org/apache/maven/plugin/coreit/HelpMojo.class" ).isFile()
-assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/plugin/coreit/HelpMojo.java" ).isFile()
-assert !new File( basedir, "target/generated-sources/plugin/HelpMojo.java" ).isFile()
+assert new File( basedir, "target/classes/org/apache/maven/its/basic_java_annotations/maven_it_basic_java_annotations/HelpMojo.class" ).isFile()
+assert new File( basedir, "target/generated-sources/plugin/org/apache/maven/its/basic_java_annotations/maven_it_basic_java_annotations/HelpMojo.java" ).isFile()
+
+mojo = pluginDescriptor.mojos.mojo.findAll{ it.goal.text() == "help"}[0]
+assert mojo.goal.text() == 'help'
+assert mojo.implementation.text() == 'org.apache.maven.its.basic_java_annotations.maven_it_basic_java_annotations.HelpMojo'
+assert mojo.language.text() == 'java'
 
 // check values set by deprecated annotation only
 mojo = pluginDescriptor.mojos.mojo.findAll{ it.goal.text() == "mplugin-396"}[0]
diff --git a/maven-plugin-plugin/src/it/mplugin-363_help-reproducible/verify.groovy b/maven-plugin-plugin/src/it/mplugin-363_help-reproducible/verify.groovy
index b64de436..b47f8a9d 100644
--- a/maven-plugin-plugin/src/it/mplugin-363_help-reproducible/verify.groovy
+++ b/maven-plugin-plugin/src/it/mplugin-363_help-reproducible/verify.groovy
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-firstRun = new File( basedir, "target/generated-sources-run1/plugin/test/HelpMojo.java" ).text;
-secondRun = new File( basedir, "target/generated-sources/plugin/test/HelpMojo.java" ).text;
+firstRun = new File( basedir, "target/generated-sources-run1/plugin/org/apache/maven/its/plugin/help/HelpMojo.java" ).text;
+secondRun = new File( basedir, "target/generated-sources/plugin/org/apache/maven/its/plugin/help/HelpMojo.java" ).text;
 
 assert firstRun == secondRun;
diff --git a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/AbstractGeneratorMojo.java b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/AbstractGeneratorMojo.java
index bd1354d5..a62d923f 100644
--- a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/AbstractGeneratorMojo.java
+++ b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/AbstractGeneratorMojo.java
@@ -19,34 +19,14 @@ package org.apache.maven.plugin.plugin;
  * under the License.
  */
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
-import org.apache.maven.artifact.resolver.filter.IncludesArtifactFilter;
+import java.util.Collections;
+import java.util.List;
+
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
-import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
-import org.apache.maven.tools.plugin.PluginToolsRequest;
-import org.apache.maven.tools.plugin.extractor.ExtractionException;
-import org.apache.maven.tools.plugin.generator.Generator;
-import org.apache.maven.tools.plugin.generator.GeneratorException;
-import org.apache.maven.tools.plugin.generator.GeneratorUtils;
-import org.apache.maven.tools.plugin.scanner.MojoScanner;
-import org.codehaus.plexus.component.repository.ComponentDependency;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.sonatype.plexus.build.incremental.BuildContext;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
 
 /**
  * Abstract class for this Plugin.
@@ -63,100 +43,19 @@ public abstract class AbstractGeneratorMojo
     @Parameter( defaultValue = "${project}", readonly = true )
     protected MavenProject project;
 
-    /**
-     * The component used for scanning the source tree for mojos.
-     */
-    @Component
-    protected MojoScanner mojoScanner;
-
-    @Component
-    protected BuildContext buildContext;
-
-    /**
-     * The file encoding of the source files.
-     *
-     * @since 2.5
-     */
-    @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
-    protected String encoding;
-
     /**
      * The goal prefix that will appear before the ":".
      */
     @Parameter
     protected String goalPrefix;
 
-    /**
-     * By default an exception is throw if no mojo descriptor is found. As the maven-plugin is defined in core, the
-     * descriptor generator mojo is bound to generate-resources phase.
-     * But for annotations, the compiled classes are needed, so skip error
-     *
-     * @since 3.0
-     */
-    @Parameter( property = "maven.plugin.skipErrorNoDescriptorsFound", defaultValue = "false" )
-    protected boolean skipErrorNoDescriptorsFound;
-
-    /**
-     * <p>
-     * The role names of mojo extractors to use.
-     * </p>
-     * <p>
-     * If not set, all mojo extractors will be used. If set to an empty extractor name, no mojo extractors
-     * will be used.
-     * </p>
-     * Example:
-     * <pre>
-     *  &lt;!-- Use all mojo extractors --&gt;
-     *  &lt;extractors/&gt;
-     *
-     *  &lt;!-- Use no mojo extractors --&gt;
-     *  &lt;extractors&gt;
-     *      &lt;extractor/&gt;
-     *  &lt;/extractors&gt;
-     *
-     *  &lt;!-- Use only bsh mojo extractor --&gt;
-     *  &lt;extractors&gt;
-     *      &lt;extractor&gt;bsh&lt;/extractor&gt;
-     *  &lt;/extractors&gt;
-     * </pre>
-     */
-    @Parameter
-    protected Set<String> extractors;
-
     /**
      * Set this to "true" to skip invoking any goals or reports of the plugin.
      *
      * @since 2.8
      */
     @Parameter( defaultValue = "false", property = "maven.plugin.skip" )
-    protected boolean skip;
-
-    /**
-     * Specify the dependencies as {@code groupId:artifactId} containing (abstract) Mojos, to filter
-     * dependencies scanned at runtime and focus on dependencies that are really useful to Mojo analysis.
-     * By default, the value is {@code null} and all dependencies are scanned (as before this parameter was added).
-     * If specified in the configuration with no children, no dependencies are scanned.
-     * 
-     * @since 3.5
-     */
-    @Parameter
-    private List<String> mojoDependencies = null;
-
-    /**
-     * List of Remote Repositories used by the resolver
-     *
-     * @since 3.0
-     */
-    @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true )
-    protected List<ArtifactRepository> remoteRepos;
-
-    /**
-     * Location of the local repository.
-     *
-     * @since 3.0
-     */
-    @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
-    protected ArtifactRepository local;
+    private boolean skip;
 
     /**
      * Maven plugin packaging types. Default is single "maven-plugin".
@@ -164,55 +63,15 @@ public abstract class AbstractGeneratorMojo
      * @since 3.3
      */
     @Parameter
-    protected List<String> packagingTypes = Collections.singletonList( "maven-plugin" );
-
-    /**
-     * Flag controlling is "expected dependencies in provided scope" check to be performed or not. Default value:
-     * {@code true}.
-     *
-     * @since 3.6.3
-     */
-    @Parameter( defaultValue = "true", property = "maven.plugin.checkExpectedProvidedScope" )
-    private boolean checkExpectedProvidedScope = true;
-
-    /**
-     * List of {@code groupId} strings of artifact coordinates that are expected to be in "provided" scope. Default
-     * value: {@code ["org.apache.maven"]}.
-     *
-     * @since 3.6.3
-     */
-    @Parameter
-    private List<String> expectedProvidedScopeGroupIds = Collections.singletonList( "org.apache.maven" );
-
-    /**
-     * List of {@code groupId:artifactId} strings of artifact coordinates that are to be excluded from "expected
-     * provided scope" check. Default value: {@code ["org.apache.maven:maven-archiver", "org.apache.maven:maven-jxr"]}.
-     *
-     * @since 3.6.3
-     */
-    @Parameter
-    private List<String> expectedProvidedScopeExclusions = Arrays.asList(
-            "org.apache.maven:maven-archiver",
-            "org.apache.maven:maven-jxr" );
-
-    /**
-     * @return the output directory where files will be generated.
-     */
-    protected abstract File getOutputDirectory();
-
-    /**
-     * @return the wanted <code>Generator</code> implementation.
-     */
-    protected abstract Generator createGenerator();
+    private List<String> packagingTypes = Collections.singletonList( "maven-plugin" );
 
     /**
      * System/OS line separator: used to format console messages.
      */
-    private static final String LS = System.lineSeparator();
+    protected static final String LS = System.lineSeparator();
+
+    protected abstract void generate() throws MojoExecutionException;
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public void execute()
         throws MojoExecutionException
@@ -222,6 +81,7 @@ public abstract class AbstractGeneratorMojo
             getLog().info( "Unsupported packaging type " + project.getPackaging() + ", execution skipped" );
             return;
         }
+
         if ( skip )
         {
             getLog().warn( "Execution skipped" );
@@ -230,7 +90,7 @@ public abstract class AbstractGeneratorMojo
 
         if ( !"maven-plugin".equalsIgnoreCase( project.getArtifactId() )
             && project.getArtifactId().toLowerCase().startsWith( "maven-" )
-            && project.getArtifactId().toLowerCase().endsWith( "-plugin" ) 
+            && project.getArtifactId().toLowerCase().endsWith( "-plugin" )
             && !"org.apache.maven.plugins".equals( project.getGroupId() ) )
         {
             getLog().error( LS + LS + "Artifact Ids of the format maven-___-plugin are reserved for" + LS
@@ -239,29 +99,8 @@ public abstract class AbstractGeneratorMojo
                                 + "In the future this error will break the build." + LS + LS );
         }
 
-        if ( checkExpectedProvidedScope )
-        {
-            Set<Artifact> wrongScopedArtifacts = dependenciesNotInProvidedScope();
-            if ( !wrongScopedArtifacts.isEmpty() )
-            {
-                StringBuilder errorMessage = new StringBuilder(
-                        LS + LS + "Some dependencies of Maven Plugins are expected to be in provided scope." + LS
-                        + "Please make sure that dependencies listed below declared in POM" + LS
-                        + "have set '<scope>provided</scope>' as well." + LS + LS
-                        + "The following dependencies are in wrong scope:" + LS
-                );
-                for ( Artifact artifact : wrongScopedArtifacts )
-                {
-                    errorMessage.append( " * " ).append( artifact ).append( LS );
-                }
-                errorMessage.append( LS ).append( LS );
-
-                getLog().error( errorMessage.toString() );
-            }
-        }
-
         String defaultGoalPrefix = getDefaultGoalPrefix( project );
-          
+
         if ( goalPrefix == null )
         {
             goalPrefix = defaultGoalPrefix;
@@ -273,67 +112,7 @@ public abstract class AbstractGeneratorMojo
                     + defaultGoalPrefix + "'." + LS );
         }
 
-        mojoScanner.setActiveExtractors( extractors );
-
-        // TODO: could use this more, eg in the writing of the plugin descriptor!
-        PluginDescriptor pluginDescriptor = new PluginDescriptor();
-
-        pluginDescriptor.setGroupId( project.getGroupId() );
-
-        pluginDescriptor.setArtifactId( project.getArtifactId() );
-
-        pluginDescriptor.setVersion( project.getVersion() );
-
-        pluginDescriptor.setGoalPrefix( goalPrefix );
-
-        pluginDescriptor.setName( project.getName() );
-
-        pluginDescriptor.setDescription( project.getDescription() );
-
-        if ( encoding == null || encoding.length() < 1 )
-        {
-            getLog().warn( "Using platform encoding (" + ReaderFactory.FILE_ENCODING
-                               + " actually) to read mojo source files, i.e. build is platform dependent!" );
-        }
-        else
-        {
-            getLog().info( "Using '" + encoding + "' encoding to read mojo source files." );
-        }
-
-        try
-        {
-            List<ComponentDependency> deps = GeneratorUtils.toComponentDependencies( project.getArtifacts() );
-            pluginDescriptor.setDependencies( deps );
-
-            PluginToolsRequest request = new DefaultPluginToolsRequest( project, pluginDescriptor );
-            request.setEncoding( encoding );
-            request.setSkipErrorNoDescriptorsFound( skipErrorNoDescriptorsFound );
-            request.setDependencies( filterMojoDependencies() );
-            request.setLocal( this.local );
-            request.setRemoteRepos( this.remoteRepos );
-
-            mojoScanner.populatePluginDescriptor( request );
-
-            File outputDirectory = getOutputDirectory();
-            outputDirectory.mkdirs();
-
-            createGenerator().execute( outputDirectory, request );
-            buildContext.refresh( outputDirectory );
-        }
-        catch ( GeneratorException e )
-        {
-            throw new MojoExecutionException( "Error writing plugin descriptor", e );
-        }
-        catch ( InvalidPluginDescriptorException | ExtractionException e )
-        {
-            throw new MojoExecutionException( "Error extracting plugin descriptor: '" + e.getLocalizedMessage() + "'",
-                                              e );
-        }
-        catch ( LinkageError e )
-        {
-            throw new MojoExecutionException( "The API of the mojo scanner is not compatible with this plugin version."
-                + " Please check the plugin dependencies configured in the POM and ensure the versions match.", e );
-        }
+        generate();
     }
 
     static String getDefaultGoalPrefix( MavenProject project )
@@ -349,61 +128,4 @@ public abstract class AbstractGeneratorMojo
         }
         return defaultGoalPrefix;
     }
-
-    /**
-     * Collects all dependencies expected to be in "provided" scope but are NOT in "provided" scope.
-     */
-    private Set<Artifact> dependenciesNotInProvidedScope()
-    {
-        LinkedHashSet<Artifact> wrongScopedDependencies = new LinkedHashSet<>();
-
-        for ( Artifact dependency : project.getArtifacts() )
-        {
-            String ga = dependency.getGroupId() + ":" + dependency.getArtifactId();
-            if ( expectedProvidedScopeGroupIds.contains( dependency.getGroupId() )
-                && !expectedProvidedScopeExclusions.contains( ga )
-                && !Artifact.SCOPE_PROVIDED.equals( dependency.getScope() ) )
-            {
-                wrongScopedDependencies.add( dependency );
-            }
-        }
-
-        return wrongScopedDependencies;
-    }
-
-    /**
-     * Get dependencies filtered with mojoDependencies configuration.
-     * 
-     * @return eventually filtered dependencies, or even <code>null</code> if configured with empty mojoDependencies
-     * list
-     * @see #mojoDependencies
-     */
-    private Set<Artifact> filterMojoDependencies()
-    {
-        Set<Artifact> filteredArtifacts;
-        if ( mojoDependencies == null )
-        {
-            filteredArtifacts = new LinkedHashSet<>( project.getArtifacts() );
-        }
-        else if ( mojoDependencies.size() == 0 )
-        {
-            filteredArtifacts = null;
-        }
-        else
-        {
-            filteredArtifacts = new LinkedHashSet<>();
-            
-            ArtifactFilter filter = new IncludesArtifactFilter( mojoDependencies );
-
-            for ( Artifact artifact : project.getArtifacts() )
-            {
-                if ( filter.include( artifact ) )
-                {
-                    filteredArtifacts.add( artifact );
-                }
-            }
-        }
-
-        return filteredArtifacts;
-    }
 }
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 9827a77f..1a6f3298 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
@@ -20,13 +20,34 @@ package org.apache.maven.plugin.plugin;
  */
 
 import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.resolver.filter.IncludesArtifactFilter;
 import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugins.annotations.Component;
 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.annotations.ResolutionScope;
-import org.apache.maven.tools.plugin.generator.Generator;
+import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
+import org.apache.maven.tools.plugin.PluginToolsRequest;
+import org.apache.maven.tools.plugin.extractor.ExtractionException;
+import org.apache.maven.tools.plugin.generator.GeneratorException;
+import org.apache.maven.tools.plugin.generator.GeneratorUtils;
 import org.apache.maven.tools.plugin.generator.PluginDescriptorGenerator;
+import org.apache.maven.tools.plugin.scanner.MojoScanner;
+import org.codehaus.plexus.component.repository.ComponentDependency;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.sonatype.plexus.build.incremental.BuildContext;
 
 /**
  * <p>
@@ -51,7 +72,15 @@ public class DescriptorGeneratorMojo
      * The directory where the generated <code>plugin.xml</code> file will be put.
      */
     @Parameter( defaultValue = "${project.build.outputDirectory}/META-INF/maven", readonly = true )
-    protected File outputDirectory;
+    private File outputDirectory;
+
+    /**
+     * The file encoding of the source files.
+     *
+     * @since 2.5
+     */
+    @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
+    private String encoding;
 
     /**
      * A flag to disable generation of the <code>plugin.xml</code> in favor of a hand authored plugin descriptor.
@@ -62,36 +91,259 @@ public class DescriptorGeneratorMojo
     private boolean skipDescriptor;
 
     /**
-     * {@inheritDoc}
+     * <p>
+     * The role names of mojo extractors to use.
+     * </p>
+     * <p>
+     * If not set, all mojo extractors will be used. If set to an empty extractor name, no mojo extractors
+     * will be used.
+     * </p>
+     * Example:
+     * <pre>
+     *  &lt;!-- Use all mojo extractors --&gt;
+     *  &lt;extractors/&gt;
+     *
+     *  &lt;!-- Use no mojo extractors --&gt;
+     *  &lt;extractors&gt;
+     *      &lt;extractor/&gt;
+     *  &lt;/extractors&gt;
+     *
+     *  &lt;!-- Use only bsh mojo extractor --&gt;
+     *  &lt;extractors&gt;
+     *      &lt;extractor&gt;bsh&lt;/extractor&gt;
+     *  &lt;/extractors&gt;
+     * </pre>
      */
-    @Override
-    protected File getOutputDirectory()
-    {
-        return outputDirectory;
-    }
+    @Parameter
+    private Set<String> extractors;
+
 
     /**
-     * {@inheritDoc}
+     * By default, an exception is throw if no mojo descriptor is found. As the maven-plugin is defined in core, the
+     * descriptor generator mojo is bound to generate-resources phase.
+     * But for annotations, the compiled classes are needed, so skip error
+     *
+     * @since 3.0
      */
-    @Override
-    protected Generator createGenerator()
-    {
-        return new PluginDescriptorGenerator( getLog() );
-    }
+    @Parameter( property = "maven.plugin.skipErrorNoDescriptorsFound", defaultValue = "false" )
+    private boolean skipErrorNoDescriptorsFound;
+
+    /**
+     * Flag controlling is "expected dependencies in provided scope" check to be performed or not. Default value:
+     * {@code true}.
+     *
+     * @since 3.6.3
+     */
+    @Parameter( defaultValue = "true", property = "maven.plugin.checkExpectedProvidedScope" )
+    private boolean checkExpectedProvidedScope = true;
+
+    /**
+     * List of {@code groupId} strings of artifact coordinates that are expected to be in "provided" scope. Default
+     * value: {@code ["org.apache.maven"]}.
+     *
+     * @since 3.6.3
+     */
+    @Parameter
+    private List<String> expectedProvidedScopeGroupIds = Collections.singletonList( "org.apache.maven" );
 
     /**
-     * {@inheritDoc}
+     * List of {@code groupId:artifactId} strings of artifact coordinates that are to be excluded from "expected
+     * provided scope" check. Default value: {@code ["org.apache.maven:maven-archiver", "org.apache.maven:maven-jxr"]}.
+     *
+     * @since 3.6.3
      */
-    @Override
-    public void execute()
+    @Parameter
+    private List<String> expectedProvidedScopeExclusions = Arrays.asList(
+        "org.apache.maven:maven-archiver",
+        "org.apache.maven:maven-jxr" );
+
+    /**
+     * Specify the dependencies as {@code groupId:artifactId} containing (abstract) Mojos, to filter
+     * dependencies scanned at runtime and focus on dependencies that are really useful to Mojo analysis.
+     * By default, the value is {@code null} and all dependencies are scanned (as before this parameter was added).
+     * If specified in the configuration with no children, no dependencies are scanned.
+     *
+     * @since 3.5
+     */
+    @Parameter
+    private List<String> mojoDependencies = null;
+
+    /**
+     * List of Remote Repositories used by the resolver
+     *
+     * @since 3.0
+     */
+    @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true )
+    private List<ArtifactRepository> remoteRepos;
+
+    /**
+     * Location of the local repository.
+     *
+     * @since 3.0
+     */
+    @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
+    private ArtifactRepository local;
+
+    /**
+     * The component used for scanning the source tree for mojos.
+     */
+    @Component
+    private MojoScanner mojoScanner;
+
+    @Component
+    protected BuildContext buildContext;
+
+    public void generate()
         throws MojoExecutionException
     {
+
         if ( skipDescriptor )
         {
+            getLog().warn( "Execution skipped" );
             return;
         }
 
-        super.execute();
+        if ( checkExpectedProvidedScope )
+        {
+            Set<Artifact> wrongScopedArtifacts = dependenciesNotInProvidedScope();
+            if ( !wrongScopedArtifacts.isEmpty() )
+            {
+                StringBuilder errorMessage = new StringBuilder(
+                    LS + LS + "Some dependencies of Maven Plugins are expected to be in provided scope." + LS
+                        + "Please make sure that dependencies listed below declared in POM" + LS
+                        + "have set '<scope>provided</scope>' as well." + LS + LS
+                        + "The following dependencies are in wrong scope:" + LS
+                );
+                for ( Artifact artifact : wrongScopedArtifacts )
+                {
+                    errorMessage.append( " * " ).append( artifact ).append( LS );
+                }
+                errorMessage.append( LS ).append( LS );
+
+                getLog().error( errorMessage.toString() );
+            }
+        }
+
+        mojoScanner.setActiveExtractors( extractors );
+
+        // TODO: could use this more, eg in the writing of the plugin descriptor!
+        PluginDescriptor pluginDescriptor = new PluginDescriptor();
+
+        pluginDescriptor.setGroupId( project.getGroupId() );
+
+        pluginDescriptor.setArtifactId( project.getArtifactId() );
+
+        pluginDescriptor.setVersion( project.getVersion() );
+
+        pluginDescriptor.setGoalPrefix( goalPrefix );
+
+        pluginDescriptor.setName( project.getName() );
+
+        pluginDescriptor.setDescription( project.getDescription() );
+
+        if ( encoding == null || encoding.length() < 1 )
+        {
+            getLog().warn( "Using platform encoding (" + ReaderFactory.FILE_ENCODING
+                               + " actually) to read mojo source files, i.e. build is platform dependent!" );
+        }
+        else
+        {
+            getLog().info( "Using '" + encoding + "' encoding to read mojo source files." );
+        }
+
+        try
+        {
+            List<ComponentDependency> deps = GeneratorUtils.toComponentDependencies( project.getArtifacts() );
+            pluginDescriptor.setDependencies( deps );
+
+            PluginToolsRequest request = new DefaultPluginToolsRequest( project, pluginDescriptor );
+            request.setEncoding( encoding );
+            request.setSkipErrorNoDescriptorsFound( skipErrorNoDescriptorsFound );
+            request.setDependencies( filterMojoDependencies() );
+            request.setLocal( this.local );
+            request.setRemoteRepos( this.remoteRepos );
+
+            mojoScanner.populatePluginDescriptor( request );
+
+            outputDirectory.mkdirs();
+
+            PluginDescriptorGenerator pluginDescriptorGenerator = new PluginDescriptorGenerator();
+            pluginDescriptorGenerator.execute( outputDirectory, request );
+
+            buildContext.refresh( outputDirectory );
+        }
+        catch ( GeneratorException e )
+        {
+            throw new MojoExecutionException( "Error writing plugin descriptor", e );
+        }
+        catch ( InvalidPluginDescriptorException | ExtractionException e )
+        {
+            throw new MojoExecutionException( "Error extracting plugin descriptor: '" + e.getLocalizedMessage() + "'",
+                                              e );
+        }
+        catch ( LinkageError e )
+        {
+            throw new MojoExecutionException( "The API of the mojo scanner is not compatible with this plugin version."
+                                                  + " Please check the plugin dependencies configured"
+                                                  + " in the POM and ensure the versions match.",
+                                              e );
+        }
     }
 
+    /**
+     * Collects all dependencies expected to be in "provided" scope but are NOT in "provided" scope.
+     */
+    private Set<Artifact> dependenciesNotInProvidedScope()
+    {
+        LinkedHashSet<Artifact> wrongScopedDependencies = new LinkedHashSet<>();
+
+        for ( Artifact dependency : project.getArtifacts() )
+        {
+            String ga = dependency.getGroupId() + ":" + dependency.getArtifactId();
+            if ( expectedProvidedScopeGroupIds.contains( dependency.getGroupId() )
+                && !expectedProvidedScopeExclusions.contains( ga )
+                && !Artifact.SCOPE_PROVIDED.equals( dependency.getScope() ) )
+            {
+                wrongScopedDependencies.add( dependency );
+            }
+        }
+
+        return wrongScopedDependencies;
+    }
+
+    /**
+     * Get dependencies filtered with mojoDependencies configuration.
+     *
+     * @return eventually filtered dependencies, or even <code>null</code> if configured with empty mojoDependencies
+     * list
+     * @see #mojoDependencies
+     */
+    private Set<Artifact> filterMojoDependencies()
+    {
+        Set<Artifact> filteredArtifacts;
+        if ( mojoDependencies == null )
+        {
+            filteredArtifacts = new LinkedHashSet<>( project.getArtifacts() );
+        }
+        else if ( mojoDependencies.isEmpty() )
+        {
+            filteredArtifacts = null;
+        }
+        else
+        {
+            filteredArtifacts = new LinkedHashSet<>();
+
+            ArtifactFilter filter = new IncludesArtifactFilter( mojoDependencies );
+
+            for ( Artifact artifact : project.getArtifacts() )
+            {
+                if ( filter.include( artifact ) )
+                {
+                    filteredArtifacts.add( artifact );
+                }
+            }
+        }
+
+        return filteredArtifacts;
+    }
 }
diff --git a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/HelpGeneratorMojo.java b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/HelpGeneratorMojo.java
index 7cc472e5..2d8a2913 100644
--- a/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/HelpGeneratorMojo.java
+++ b/maven-plugin-plugin/src/main/java/org/apache/maven/plugin/plugin/HelpGeneratorMojo.java
@@ -19,7 +19,11 @@ package org.apache.maven.plugin.plugin;
  * under the License.
  */
 
+import javax.lang.model.SourceVersion;
+
 import java.io.File;
+import java.util.Arrays;
+import java.util.stream.Collectors;
 
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.Component;
@@ -27,19 +31,19 @@ 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.annotations.ResolutionScope;
-import org.apache.maven.tools.plugin.generator.Generator;
+import org.apache.maven.tools.plugin.generator.GeneratorException;
 import org.apache.maven.tools.plugin.generator.PluginHelpGenerator;
+import org.codehaus.plexus.util.StringUtils;
 import org.codehaus.plexus.velocity.VelocityComponent;
 
 /**
  * Generates a <code>HelpMojo</code> class.
- * 
- * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
  *
+ * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
  * @since 2.4
  */
 @Mojo( name = "helpmojo", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true,
-                requiresDependencyResolution = ResolutionScope.COMPILE )
+       requiresDependencyResolution = ResolutionScope.COMPILE )
 public class HelpGeneratorMojo
     extends AbstractGeneratorMojo
 {
@@ -50,9 +54,14 @@ public class HelpGeneratorMojo
     protected File outputDirectory;
 
     /**
-     * The name of the package for the generated <code>HelpMojo</code>. By default, the package will be calculated based
-     * on the packages of the other plugin goals.
-     * 
+     * The name of the package for the generated <code>HelpMojo</code>.
+     * <p>
+     * By default, the package name will be calculated as <code>groupId + "." + artifactId</code> with additional
+     * <ul>
+     * <li><code>-</code> (dashes) will be replaced by <code>_</code> (underscores)</li>
+     * <li><code>_</code> (underscore) will be added before each number or Java keyword at the beginning of name</li>
+     * </ul>
+     *
      * @since 2.6
      */
     @Parameter
@@ -64,41 +73,59 @@ public class HelpGeneratorMojo
     @Component
     private VelocityComponent velocity;
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected File getOutputDirectory()
+    String getHelpPackageName()
     {
-        return outputDirectory;
+        String packageName = null;
+        if ( StringUtils.isNotBlank( helpPackageName ) )
+        {
+            packageName = helpPackageName;
+        }
+
+        if ( packageName == null )
+        {
+            packageName = project.getGroupId() + "." + project.getArtifactId();
+            packageName = packageName.replace( "-", "_" );
+
+            String[] packageItems = packageName.split( "\\." );
+            packageName = Arrays.stream( packageItems )
+                .map( this::prefixSpecialCase )
+                .collect( Collectors.joining( "." ) );
+        }
+
+        return packageName;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected Generator createGenerator()
+    private String prefixSpecialCase( String name )
     {
-        return new PluginHelpGenerator().setHelpPackageName( helpPackageName ).setVelocityComponent( this.velocity );
+        if ( SourceVersion.isKeyword( name ) || !Character.isJavaIdentifierStart( name.charAt( 0 ) ) )
+        {
+            name = "_" + name;
+        }
+        return name;
     }
 
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public void execute()
-        throws MojoExecutionException
+    protected void generate() throws MojoExecutionException
     {
-        // force value for this plugin
-        skipErrorNoDescriptorsFound = true;
+        PluginHelpGenerator pluginHelpGenerator = new PluginHelpGenerator()
+            .setMavenProject( project )
+            .setHelpPackageName( getHelpPackageName() )
+            .setGoalPrefix( goalPrefix )
+            .setVelocityComponent( velocity );
 
-        super.execute();
+        try
+        {
+            pluginHelpGenerator.execute( outputDirectory );
+        }
+        catch ( GeneratorException e )
+        {
+            throw new MojoExecutionException( e.getMessage(), e );
+        }
 
-        if ( !project.getCompileSourceRoots().contains( outputDirectory.getAbsolutePath() ) && !skip )
+        if ( !project.getCompileSourceRoots().contains( outputDirectory.getAbsolutePath() ) )
         {
             project.addCompileSourceRoot( outputDirectory.getAbsolutePath() );
         }
-
     }
 
 }
diff --git a/maven-plugin-plugin/src/test/java/org/apache/maven/plugin/plugin/HelpGeneratorMojoTest.java b/maven-plugin-plugin/src/test/java/org/apache/maven/plugin/plugin/HelpGeneratorMojoTest.java
new file mode 100644
index 00000000..5d657091
--- /dev/null
+++ b/maven-plugin-plugin/src/test/java/org/apache/maven/plugin/plugin/HelpGeneratorMojoTest.java
@@ -0,0 +1,63 @@
+package org.apache.maven.plugin.plugin;
+
+/*
+ * 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.
+ */
+
+import java.util.stream.Stream;
+
+import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class HelpGeneratorMojoTest
+{
+
+    public static Stream<Arguments> packageNameShouldBeCorrect()
+    {
+        return Stream.of(
+            Arguments.of( aProject( "groupId", "artifactId" ), "groupId.artifactId" ),
+            Arguments.of( aProject( "groupId", "123-artifactId" ), "groupId._123_artifactId" ),
+            Arguments.of( aProject( "group-Id", "artifact-Id" ), "group_Id.artifact_Id" ),
+            Arguments.of( aProject( "group-Id", "int" ), "group_Id._int" )
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource
+    void packageNameShouldBeCorrect( MavenProject project, String expectedPackageName )
+    {
+        HelpGeneratorMojo mojo = new HelpGeneratorMojo();
+        mojo.project = project;
+
+        String packageName = mojo.getHelpPackageName();
+        assertEquals( expectedPackageName, packageName );
+    }
+
+    private static MavenProject aProject( String groupId, String artifactId )
+    {
+
+        MavenProject mavenProject = new MavenProject();
+        mavenProject.setGroupId( groupId );
+        mavenProject.setArtifactId( artifactId );
+        return mavenProject;
+    }
+}
diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java
index 6e777c08..70581131 100644
--- a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java
+++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginDescriptorGenerator.java
@@ -19,8 +19,6 @@ package org.apache.maven.tools.plugin.generator;
  * under the License.
  */
 
-import static java.nio.charset.StandardCharsets.UTF_8;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -31,12 +29,11 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import org.apache.maven.plugin.descriptor.DuplicateMojoDescriptorException;
+
 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.Requirement;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.tools.plugin.ExtendedMojoDescriptor;
 import org.apache.maven.tools.plugin.PluginToolsRequest;
@@ -45,6 +42,8 @@ import org.codehaus.plexus.util.StringUtils;
 import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
 import org.codehaus.plexus.util.xml.XMLWriter;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 /**
  * Generate a <a href="/ref/current/maven-plugin-api/plugin.html">Maven Plugin Descriptor XML file</a> and
  * corresponding <code>plugin-help.xml</code> help content for {@link PluginHelpGenerator}.
@@ -54,20 +53,10 @@ public class PluginDescriptorGenerator
     implements Generator
 {
 
-    private final Log log;
-
-    public PluginDescriptorGenerator( Log log )
-    {
-        this.log = log;
-    }
-
     @Override
     public void execute( File destinationDirectory, PluginToolsRequest request )
         throws GeneratorException
     {
-        // eventually rewrite help mojo class to match actual package name
-        PluginHelpGenerator.rewriteHelpMojo( request, log );
-
         try
         {
             // write complete plugin.xml descriptor
@@ -86,10 +75,6 @@ public class PluginDescriptorGenerator
         {
             throw new GeneratorException( e.getMessage(), e );
         }
-        catch ( DuplicateMojoDescriptorException e )
-        {
-            throw new GeneratorException( e.getMessage(), e );
-        }
     }
 
     private String getVersion()
@@ -100,7 +85,7 @@ public class PluginDescriptorGenerator
     }
 
     public void writeDescriptor( File destinationFile, PluginToolsRequest request, boolean helpDescriptor )
-        throws IOException, DuplicateMojoDescriptorException
+        throws IOException
     {
         PluginDescriptor pluginDescriptor = request.getPluginDescriptor();
 
@@ -169,11 +154,6 @@ public class PluginDescriptorGenerator
         }
     }
 
-    protected void processMojoDescriptor( MojoDescriptor mojoDescriptor, XMLWriter w )
-    {
-        processMojoDescriptor( mojoDescriptor, w, false );
-    }
-
     /**
      * @param mojoDescriptor not null
      * @param w              not null
diff --git a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java
index d430e5a0..9149712c 100644
--- a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java
+++ b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginHelpGenerator.java
@@ -19,79 +19,42 @@ package org.apache.maven.tools.plugin.generator;
  * under the License.
  */
 
-import static java.nio.charset.StandardCharsets.UTF_8;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
 
-import org.apache.maven.plugin.descriptor.MojoDescriptor;
-import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
-import org.apache.maven.tools.plugin.PluginToolsRequest;
 import org.apache.velocity.VelocityContext;
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 import org.codehaus.plexus.logging.Logger;
 import org.codehaus.plexus.logging.console.ConsoleLogger;
 import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.IOUtil;
-import org.codehaus.plexus.util.PropertyUtils;
 import org.codehaus.plexus.util.StringUtils;
 import org.codehaus.plexus.velocity.VelocityComponent;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.commons.ClassRemapper;
-import org.objectweb.asm.commons.Remapper;
-import org.objectweb.asm.commons.SimpleRemapper;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Reader;
-import java.io.StringWriter;
-import java.nio.charset.Charset;
-import java.util.List;
-import java.util.Properties;
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
  * Generates an <code>HelpMojo</code> class from <code>help-class-source.vm</code> template.
  * The generated mojo reads help content from <code>META-INF/maven/${groupId}/${artifactId}/plugin-help.xml</code>
  * resource, which is generated by this {@link PluginDescriptorGenerator}.
- * <p>Notice that the help mojo source needs to be generated before compilation, but when Java annotations are used,
- * plugin descriptor content is available only after compilation (detecting annotations in .class files):
- * help mojo source can be generated with empty package only (and no plugin descriptor available yet), then needs
- * to be updated after compilation - through {@link #rewriteHelpMojo(PluginToolsRequest, Log)} which is called from
- * plugin descriptor XML generation.</p>
  *
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
  * @since 2.4
  */
 public class PluginHelpGenerator
     extends AbstractLogEnabled
-    implements Generator
 {
     /**
      * Default generated class name
      */
     private static final String HELP_MOJO_CLASS_NAME = "HelpMojo";
 
-    /**
-     * Help properties file, to store data about generated source.
-     */
-    private static final String HELP_PROPERTIES_FILENAME = "maven-plugin-help.properties";
-
-    /**
-     * Default goal
-     */
-    private static final String HELP_GOAL = "help";
-
     private String helpPackageName;
-
-    private boolean useAnnotations;
-
+    private String goalPrefix;
+    private MavenProject mavenProject;
     private VelocityComponent velocityComponent;
 
     /**
@@ -106,41 +69,10 @@ public class PluginHelpGenerator
     // Public methods
     // ----------------------------------------------------------------------
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void execute( File destinationDirectory, PluginToolsRequest request )
+    public void execute( File destinationDirectory )
         throws GeneratorException
     {
-        PluginDescriptor pluginDescriptor = request.getPluginDescriptor();
-
-        String helpImplementation = getImplementation( pluginDescriptor );
-
-        List<MojoDescriptor> mojoDescriptors = pluginDescriptor.getMojos();
-
-        if ( mojoDescriptors != null )
-        {
-            // Verify that no help goal already exists
-            MojoDescriptor descriptor = pluginDescriptor.getMojo( HELP_GOAL );
-
-            if ( ( descriptor != null ) && !descriptor.getImplementation().equals( helpImplementation ) )
-            {
-                if ( getLogger().isWarnEnabled() )
-                {
-                    getLogger().warn( "\n\nA help goal (" + descriptor.getImplementation()
-                                          + ") already exists in this plugin. SKIPPED THE " + helpImplementation
-                                          + " GENERATION.\n" );
-                }
-
-                return;
-            }
-        }
-
-        writeHelpPropertiesFile( request, destinationDirectory );
-
-        useAnnotations = request.getProject().getArtifactMap().containsKey(
-            "org.apache.maven.plugin-tools:maven-plugin-annotations" );
+        String helpImplementation = getImplementation();
 
         try
         {
@@ -150,9 +82,9 @@ public class PluginHelpGenerator
             helpClass.getParentFile().mkdirs();
 
             String helpClassSources =
-                getHelpClassSources( getPluginHelpPath( request.getProject() ), pluginDescriptor );
+                getHelpClassSources( getPluginHelpPath( mavenProject ) );
 
-            FileUtils.fileWrite( helpClass, request.getEncoding(), helpClassSources );
+            FileUtils.fileWrite( helpClass, UTF_8.name(), helpClassSources );
         }
         catch ( IOException e )
         {
@@ -166,14 +98,21 @@ public class PluginHelpGenerator
         return this;
     }
 
-    public VelocityComponent getVelocityComponent()
+    public PluginHelpGenerator setVelocityComponent( VelocityComponent velocityComponent )
     {
-        return velocityComponent;
+        this.velocityComponent = velocityComponent;
+        return this;
     }
 
-    public PluginHelpGenerator setVelocityComponent( VelocityComponent velocityComponent )
+    public PluginHelpGenerator setGoalPrefix( String goalPrefix )
     {
-        this.velocityComponent = velocityComponent;
+        this.goalPrefix = goalPrefix;
+        return this;
+    }
+
+    public PluginHelpGenerator setMavenProject( MavenProject mavenProject )
+    {
+        this.mavenProject = mavenProject;
         return this;
     }
 
@@ -181,21 +120,17 @@ public class PluginHelpGenerator
     // Private methods
     // ----------------------------------------------------------------------
 
-    private String getHelpClassSources( String pluginHelpPath, PluginDescriptor pluginDescriptor )
+    private String getHelpClassSources( String pluginHelpPath )
         throws IOException
     {
         VelocityContext context = new VelocityContext();
-        if ( this.helpPackageName != null )
-        {
-            context.put( "helpPackageName", this.helpPackageName );
-        }
-        else
-        {
-            context.put( "helpPackageName", "" );
-        }
+        boolean useAnnotations = mavenProject.getArtifactMap().containsKey(
+            "org.apache.maven.plugin-tools:maven-plugin-annotations" );
+
+        context.put( "helpPackageName", helpPackageName );
         context.put( "pluginHelpPath", pluginHelpPath );
-        context.put( "artifactId", pluginDescriptor.getArtifactId() );
-        context.put( "goalPrefix", pluginDescriptor.getGoalPrefix() );
+        context.put( "artifactId", mavenProject.getArtifactId() );
+        context.put( "goalPrefix", goalPrefix );
         context.put( "useAnnotations", useAnnotations );
 
         StringWriter stringWriter = new StringWriter();
@@ -214,226 +149,17 @@ public class PluginHelpGenerator
     }
 
     /**
-     * @param pluginDescriptor The descriptor of the plugin for which to generate a help goal, must not be
-     *                         <code>null</code>.
      * @return The implementation.
      */
-    private String getImplementation( PluginDescriptor pluginDescriptor )
+    private String getImplementation( )
     {
-        if ( StringUtils.isEmpty( helpPackageName ) )
-        {
-            helpPackageName = GeneratorUtils.discoverPackageName( pluginDescriptor );
-        }
-
         return StringUtils.isEmpty( helpPackageName )
             ? HELP_MOJO_CLASS_NAME
             : helpPackageName + '.' + HELP_MOJO_CLASS_NAME;
     }
 
-    /**
-     * Write help properties files for later use to eventually rewrite Help Mojo.
-     *
-     * @param request
-     * @throws GeneratorException
-     * @see {@link #rewriteHelpMojo(PluginToolsRequest, Log)}
-     */
-    private void writeHelpPropertiesFile( PluginToolsRequest request, File destinationDirectory )
-        throws GeneratorException
-    {
-        Properties properties = new Properties();
-        properties.put( "helpPackageName", helpPackageName == null ? "" : helpPackageName );
-        properties.put( "destinationDirectory", destinationDirectory.getAbsolutePath() );
-
-        File tmpPropertiesFile = new File( request.getProject().getBuild().getDirectory(), HELP_PROPERTIES_FILENAME );
-
-        if ( tmpPropertiesFile.exists() )
-        {
-            tmpPropertiesFile.delete();
-        }
-        else if ( !tmpPropertiesFile.getParentFile().exists() )
-        {
-            tmpPropertiesFile.getParentFile().mkdirs();
-        }
-
-        try ( FileOutputStream fos = new FileOutputStream( tmpPropertiesFile ) )
-        {
-            properties.store( fos, "maven plugin help mojo generation informations" );
-        }
-        catch ( IOException e )
-        {
-            throw new GeneratorException( e.getMessage(), e );
-        }
-    }
-
     static String getPluginHelpPath( MavenProject mavenProject )
     {
         return mavenProject.getGroupId() + "/" + mavenProject.getArtifactId() + "/plugin-help.xml";
     }
-
-    /**
-     * Rewrite Help Mojo to match actual Mojos package name if it was not available at source generation
-     * time. This is used at descriptor generation time.
-     *
-     * @param request
-     * @throws GeneratorException
-     */
-    static void rewriteHelpMojo( PluginToolsRequest request, Log log )
-        throws GeneratorException
-    {
-        File tmpPropertiesFile = new File( request.getProject().getBuild().getDirectory(), HELP_PROPERTIES_FILENAME );
-
-        if ( !tmpPropertiesFile.exists() )
-        {
-            return;
-        }
-
-        Properties properties;
-        try
-        {
-            properties = PropertyUtils.loadProperties( tmpPropertiesFile );
-        }
-        catch ( IOException e )
-        {
-            throw new GeneratorException( e.getMessage(), e );
-        }
-
-        String helpPackageName = properties.getProperty( "helpPackageName" );
-
-        // if helpPackageName property is empty, we have to rewrite the class with a better package name than empty
-        if ( StringUtils.isEmpty( helpPackageName ) )
-        {
-            String destDir = properties.getProperty( "destinationDirectory" );
-            File destinationDirectory;
-            if ( StringUtils.isEmpty( destDir ) )
-            {
-                // writeHelpPropertiesFile() creates 2 properties: find one without the other should not be possible
-                log.warn( "\n\nUnexpected situation: destinationDirectory not defined in " + HELP_PROPERTIES_FILENAME
-                              + " during help mojo source generation but expected during XML descriptor generation." );
-                log.warn( "Please check helpmojo goal version used in previous build phase." );
-                log.warn( "If you just upgraded to plugin-tools >= 3.2 you must run a clean build at least once." );
-                destinationDirectory = new File( "target/generated-sources/plugin" );
-                log.warn( "Trying default location: " + destinationDirectory );
-            }
-            else
-            {
-                destinationDirectory = new File( destDir );
-            }
-            String helpMojoImplementation = rewriteHelpClassToMojoPackage( request, destinationDirectory, log );
-
-            if ( helpMojoImplementation != null )
-            {
-                // rewrite plugin descriptor with new HelpMojo implementation class
-                updateHelpMojoDescriptor( request.getPluginDescriptor(), helpMojoImplementation );
-            }
-        }
-    }
-
-    private static String rewriteHelpClassToMojoPackage( PluginToolsRequest request, File destinationDirectory,
-                                                         Log log )
-        throws GeneratorException
-    {
-        String destinationPackage = GeneratorUtils.discoverPackageName( request.getPluginDescriptor() );
-        if ( StringUtils.isEmpty( destinationPackage ) )
-        {
-            return null;
-        }
-        String packageAsDirectory = StringUtils.replace( destinationPackage, '.', '/' );
-
-        String outputDirectory = request.getProject().getBuild().getOutputDirectory();
-        File helpClassFile = new File( outputDirectory, HELP_MOJO_CLASS_NAME + ".class" );
-        if ( !helpClassFile.exists() )
-        {
-            return null;
-        }
-
-        // rewrite help mojo source
-        File helpSourceFile = new File( destinationDirectory, HELP_MOJO_CLASS_NAME + ".java" );
-        if ( !helpSourceFile.exists() )
-        {
-            log.warn( "HelpMojo.java not found in default location: " + helpSourceFile.getAbsolutePath() );
-            log.warn( "Help goal source won't be moved to package: " + destinationPackage );
-        }
-        else
-        {
-            File helpSourceFileNew =
-                new File( destinationDirectory, packageAsDirectory + '/' + HELP_MOJO_CLASS_NAME + ".java" );
-            if ( !helpSourceFileNew.getParentFile().exists() )
-            {
-                helpSourceFileNew.getParentFile().mkdirs();
-            }
-            Charset encoding = Charset.forName( request.getEncoding() );
-            try ( Reader sourceReader = new InputStreamReader( new FileInputStream( helpSourceFile ), //
-                                                              encoding ); //
-                 PrintWriter sourceWriter = new PrintWriter(
-                     new OutputStreamWriter( new FileOutputStream( helpSourceFileNew ), //
-                                             encoding ) ) )
-            {
-                sourceWriter.println( "package " + destinationPackage + ";" );
-                IOUtil.copy( sourceReader, sourceWriter );
-            }
-            catch ( IOException e )
-            {
-                throw new GeneratorException( e.getMessage(), e );
-            }
-            helpSourceFileNew.setLastModified( helpSourceFile.lastModified() );
-            helpSourceFile.delete();
-        }
-
-        // rewrite help mojo .class
-        File rewriteHelpClassFile =
-            new File( outputDirectory + '/' + packageAsDirectory, HELP_MOJO_CLASS_NAME + ".class" );
-        if ( !rewriteHelpClassFile.getParentFile().exists() )
-        {
-            rewriteHelpClassFile.getParentFile().mkdirs();
-        }
-
-        ClassReader cr;
-        try ( FileInputStream fileInputStream = new FileInputStream( helpClassFile ) )
-        {
-            cr = new ClassReader( fileInputStream );
-        }
-        catch ( IOException e )
-        {
-            throw new GeneratorException( e.getMessage(), e );
-        }
-
-        ClassWriter cw = new ClassWriter( 0 );
-
-        Remapper packageRemapper =
-            new SimpleRemapper( HELP_MOJO_CLASS_NAME, packageAsDirectory + '/' + HELP_MOJO_CLASS_NAME );
-        ClassVisitor cv = new ClassRemapper( cw, packageRemapper );
-
-        try
-        {
-            cr.accept( cv, ClassReader.EXPAND_FRAMES );
-        }
-        catch ( Throwable e )
-        {
-            throw new GeneratorException( "ASM issue processing class-file " + helpClassFile.getPath(), e );
-        }
-
-        byte[] renamedClass = cw.toByteArray();
-        try ( FileOutputStream fos = new FileOutputStream( rewriteHelpClassFile ) )
-        {
-            fos.write( renamedClass );
-        }
-        catch ( IOException e )
-        {
-            throw new GeneratorException( "Error rewriting help class: " + e.getMessage(), e );
-        }
-
-        helpClassFile.delete();
-
-        return destinationPackage + ".HelpMojo";
-    }
-
-    private static void updateHelpMojoDescriptor( PluginDescriptor pluginDescriptor, String helpMojoImplementation )
-    {
-        MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( HELP_GOAL );
-
-        if ( mojoDescriptor != null )
-        {
-            mojoDescriptor.setImplementation( helpMojoImplementation );
-        }
-    }
 }
diff --git a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginHelpGeneratorTest.java b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginHelpGeneratorTest.java
deleted file mode 100644
index e82453d0..00000000
--- a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginHelpGeneratorTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.apache.maven.tools.plugin.generator;
-
-/*
- * 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.
- */
-
-import javax.inject.Inject;
-
-import org.codehaus.plexus.testing.PlexusTest;
-import org.codehaus.plexus.velocity.VelocityComponent;
-
-/**
- * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
- */
-@PlexusTest
-public class PluginHelpGeneratorTest
-    extends AbstractGeneratorTestCase
-{
-
-    @Inject
-    VelocityComponent velocityComponent;
-
-    // inherits tests from base class
-    @Override
-    protected void setupGenerator()
-        throws Exception
-    {
-        generator = new PluginHelpGenerator().setVelocityComponent( velocityComponent );
-
-    }
-}
diff --git a/maven-plugin-tools-java/src/test/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaMojoDescriptorExtractorTest.java b/maven-plugin-tools-java/src/test/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaMojoDescriptorExtractorTest.java
index b804d2f8..e734dc7f 100644
--- a/maven-plugin-tools-java/src/test/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaMojoDescriptorExtractorTest.java
+++ b/maven-plugin-tools-java/src/test/java/org/apache/maven/tools/plugin/extractor/javadoc/JavaMojoDescriptorExtractorTest.java
@@ -128,7 +128,7 @@ public class JavaMojoDescriptorExtractorTest
             request.getPluginDescriptor().addMojo( mojoDescriptor );
         }
 
-        Generator descriptorGenerator = new PluginDescriptorGenerator( new SystemStreamLog() );
+        Generator descriptorGenerator = new PluginDescriptorGenerator();
 
         descriptorGenerator.execute( new File( root, directory ), request );
 
diff --git a/pom.xml b/pom.xml
index c1ea31da..943f5cc4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -90,7 +90,7 @@
   </distributionManagement>
 
   <properties>
-    <surefire.version>2.22.2</surefire.version>
+    <surefire.version>3.0.0-M7</surefire.version>
     <javaVersion>8</javaVersion>
     <pluginTestingHarnessVersion>3.3.0</pluginTestingHarnessVersion>
     <mavenVersion>3.2.5</mavenVersion>
@@ -247,10 +247,11 @@
         <scope>test</scope>
       </dependency>
       <dependency>
-        <groupId>org.junit.jupiter</groupId>
-        <artifactId>junit-jupiter-engine</artifactId>
+        <groupId>org.junit</groupId>
+        <artifactId>junit-bom</artifactId>
         <version>5.8.2</version>
-        <scope>test</scope>
+        <type>pom</type>
+        <scope>import</scope>
       </dependency>
       <dependency>
         <groupId>org.codehaus.plexus</groupId>