You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by kw...@apache.org on 2022/11/04 16:29:05 UTC

[maven-plugin-tools] branch feature/set-required-maven-and-java-version updated (0a4206af -> 2fa5b370)

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

kwin pushed a change to branch feature/set-required-maven-and-java-version
in repository https://gitbox.apache.org/repos/asf/maven-plugin-tools.git


 discard 0a4206af [MPLUGIN-425] Add required Java and Maven version to the generated plugin descriptor
     new 2fa5b370 [MPLUGIN-425] Add required Java and Maven version to the generated plugin descriptor

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (0a4206af)
            \
             N -- N -- N   refs/heads/feature/set-required-maven-and-java-version (2fa5b370)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy | 3 +++
 1 file changed, 3 insertions(+)


[maven-plugin-tools] 01/01: [MPLUGIN-425] Add required Java and Maven version to the generated plugin descriptor

Posted by kw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/set-required-maven-and-java-version
in repository https://gitbox.apache.org/repos/asf/maven-plugin-tools.git

commit 2fa5b3706aa33f04179e62f2df4646f79894f711
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Fri Nov 4 16:47:08 2022 +0100

    [MPLUGIN-425] Add required Java and Maven version to the generated
    plugin descriptor
---
 .../src/it/java-basic-annotations/verify.groovy    |   3 +
 .../plugin/plugin/DescriptorGeneratorMojo.java     |  96 +++++++
 .../JavaAnnotationsMojoDescriptorExtractor.java    |  55 +++-
 .../scanner/DefaultMojoAnnotationsScanner.java     |  45 +++-
 .../annotations/scanner/MojoAnnotatedClass.java    |  21 +-
 .../scanner/MojoAnnotationsScannerRequest.java     |  12 +
 .../tools/plugin/DefaultPluginToolsRequest.java    |  36 ++-
 .../maven/tools/plugin/ExtendedMojoDescriptor.java |  61 ++---
 .../tools/plugin/ExtendedPluginDescriptor.java     | 282 +++++++++++++++++++++
 .../maven/tools/plugin/PluginToolsRequest.java     |  30 +++
 .../plugin/extractor/MojoDescriptorExtractor.java  |  17 +-
 .../generator/PluginDescriptorFilesGenerator.java  |  15 ++
 12 files changed, 622 insertions(+), 51 deletions(-)

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 4315bef7..248086e8 100644
--- a/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy
+++ b/maven-plugin-plugin/src/it/java-basic-annotations/verify.groovy
@@ -25,6 +25,9 @@ assert descriptorFile.isFile()
 
 def pluginDescriptor = new XmlParser().parse( descriptorFile );
 
+assert pluginDescriptor.requiredJavaVersion.text() == '1.8'
+assert pluginDescriptor.requiredMavenVersion == '3.2.5'
+
 def mojo = pluginDescriptor.mojos.mojo.findAll{ it.goal.text() == "first" }[0]
 
 assert mojo.goal.text() == 'first'
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 0954a727..c2da73dd 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
@@ -41,6 +41,7 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
 import org.apache.maven.settings.Settings;
 import org.apache.maven.tools.plugin.DefaultPluginToolsRequest;
+import org.apache.maven.tools.plugin.ExtendedPluginDescriptor;
 import org.apache.maven.tools.plugin.PluginToolsRequest;
 import org.apache.maven.tools.plugin.extractor.ExtractionException;
 import org.apache.maven.tools.plugin.generator.GeneratorException;
@@ -70,6 +71,9 @@ import org.sonatype.plexus.build.incremental.BuildContext;
 public class DescriptorGeneratorMojo
     extends AbstractGeneratorMojo
 {
+    private static final String VALUE_AUTO = "auto";
+    private static final String VALUE_NONE = "none";
+
     /**
      * The directory where the generated <code>plugin.xml</code> file will be put.
      */
@@ -235,6 +239,43 @@ public class DescriptorGeneratorMojo
     @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
     private ArtifactRepository local;
 
+    /**
+     * The required Java version to set in the plugin descriptor. This is evaluated by Maven 4 and ignored by earlier
+     * Maven versions. Can be either one of the following formats:
+     * 
+     * <ul>
+     * <li>One of the values as for <a href="https://maven.apache.org/pom.html#Activation">POM profile activation
+     * element {@code jdk}</a>, i.e. version ranges, version prefixes
+     * and negated version prefixes (starting with '!').</li>
+     * <li>{@code "auto"} to determine the minimum Java version from the binary class version being generated during
+     * compilation (determined by the extractor).</li>
+     * <li>{@code "none"} to not set a required Java version.</li>
+     * </ul>
+     * @since 3.8.0
+     */
+    @Parameter( defaultValue = VALUE_AUTO )
+    String requiredJavaVersion;
+
+    /**
+     * The required Maven version to set in the plugin descriptor. This is evaluated by Maven 4 and ignored by earlier
+     * Maven versions. Can be either one of the following formats:
+     * 
+     * <ul>
+     * <li>A version range which specifies the supported Maven versions. It can either use the usual mathematical
+     * syntax like {@code "[2.0.10,2.1.0),[3.0,)"} or use a single version like {@code "2.2.1"}. The latter is a short
+     * form for {@code "[2.2.1,)"}, i.e. denotes the minimum version required.</li>
+     * <li>{@code "auto"} to determine the minimum Maven version from the POMs Maven prerequisite, or if not set the
+     * referenced Maven API version.</li>
+     * <li>{@code "none"} to not set a required Maven version.</li>
+     * </ul>
+     * This value (if not set to {@code "none"}) takes precedence over the 
+     * <a href="https://maven.apache.org/pom.html#Prerequisites">POMs Maven prerequisite</a> in Maven 4.
+     * 
+     * @since 3.8.0
+     */
+    @Parameter( defaultValue = VALUE_AUTO )
+    String requiredMavenVersion;
+
     /**
      * The component used for scanning the source tree for mojos.
      */
@@ -335,6 +376,7 @@ public class DescriptorGeneratorMojo
             request.setSettings( settings );
 
             mojoScanner.populatePluginDescriptor( request );
+            request.setPluginDescriptor( extendPluginDescriptor( request ) );
 
             outputDirectory.mkdirs();
 
@@ -361,6 +403,60 @@ public class DescriptorGeneratorMojo
         }
     }
 
+    private PluginDescriptor extendPluginDescriptor( PluginToolsRequest request )
+    {
+        ExtendedPluginDescriptor extendedPluginDescriptor = 
+                        new ExtendedPluginDescriptor( request.getPluginDescriptor() );
+        if ( !VALUE_NONE.equals( requiredJavaVersion ) )
+        {
+            extendedPluginDescriptor.setRequiredJavaVersion( getRequiredJavaVersion( request ) );
+        }
+        if ( !VALUE_NONE.equals( requiredMavenVersion ) )
+        {
+            extendedPluginDescriptor.setRequiredMavenVersion( getRequiredMavenVersion( request ) );
+        }
+        return extendedPluginDescriptor;
+    }
+
+    private String getRequiredMavenVersion( PluginToolsRequest request )
+    {
+        if ( !VALUE_AUTO.equals( requiredMavenVersion ) )
+        {
+            return requiredMavenVersion;
+        }
+        getLog().debug( "Trying to derive Maven version automatically from project prerequisites..." );
+        String requiredMavenVersion = project.getPrerequisites() != null ? project.getPrerequisites().getMaven()
+                                        : null;
+        if ( requiredMavenVersion == null )
+        {
+            getLog().debug( "Trying to derive Maven version automatically from referenced Maven Plugin API artifact "
+                            + "version..." );
+            requiredMavenVersion = request.getUsedMavenApiVersion();
+        }
+        if ( requiredMavenVersion == null )
+        {
+            getLog().warn( "Cannot determine the required Maven version automatically, it is recommended to "
+                + "configure some explicit value manually." );
+        }
+        return requiredMavenVersion;
+    }
+
+    private String getRequiredJavaVersion( PluginToolsRequest request )
+    {
+        if ( !VALUE_AUTO.equals( requiredJavaVersion ) )
+        {
+            return requiredJavaVersion;
+        }
+        String requiredJavaVersion = request.getRequiredJavaVersion();
+        if ( requiredJavaVersion == null )
+        {
+            getLog().warn( "Cannot determine the required Java version automatically, it is recommended to "
+                            + "configure some explicit value manually." );
+        }
+        
+        return requiredJavaVersion;
+    }
+
     /**
      * Collects all dependencies expected to be in "provided" scope but are NOT in "provided" scope.
      */
diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java
index facfe4a4..e083d88b 100644
--- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java
+++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java
@@ -36,6 +36,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
@@ -52,6 +53,7 @@ import com.thoughtworks.qdox.model.JavaMethod;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.artifact.versioning.ComparableVersion;
 import org.apache.maven.plugin.descriptor.DuplicateParameterException;
 import org.apache.maven.plugin.descriptor.InvalidParameterException;
 import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException;
@@ -102,6 +104,43 @@ public class JavaAnnotationsMojoDescriptorExtractor
 
     private static final GroupKey GROUP_KEY = new GroupKey( GroupKey.JAVA_GROUP, 100 );
 
+    /**
+     * 
+     * @see <a href="https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-4.html#jvms-4.1">JVMS 4.1</a>
+     */
+    private static final Map<Short, String> MAJOR_CLASS_VERSION_TO_JAVA_STRING;
+    static
+    {
+        MAJOR_CLASS_VERSION_TO_JAVA_STRING = initClassVersionMap();
+    }
+ 
+    @SuppressWarnings( "checkstyle:magicnumber" )
+    private static Map<Short, String> initClassVersionMap()
+    {
+        Map<Short, String> classVersionMap = new HashMap<>();
+        classVersionMap.put( (short) 45, "1.1" );
+        classVersionMap.put( (short) 46, "1.2" );
+        classVersionMap.put( (short) 47, "1.3" );
+        classVersionMap.put( (short) 48, "1.4" );
+        classVersionMap.put( (short) 49, "1.5" );
+        classVersionMap.put( (short) 50, "1.6" );
+        classVersionMap.put( (short) 51, "1.7" );
+        classVersionMap.put( (short) 52, "1.8" );
+        classVersionMap.put( (short) 53, "9" );
+        classVersionMap.put( (short) 54, "10" );
+        classVersionMap.put( (short) 55, "11" );
+        classVersionMap.put( (short) 56, "12" );
+        classVersionMap.put( (short) 57, "13" );
+        classVersionMap.put( (short) 58, "14" );
+        classVersionMap.put( (short) 59, "15" );
+        classVersionMap.put( (short) 60, "16" );
+        classVersionMap.put( (short) 61, "17" );
+        classVersionMap.put( (short) 62, "18" );
+        classVersionMap.put( (short) 63, "19" );
+        classVersionMap.put( (short) 64, "20" );
+        return classVersionMap;
+    }
+
     @Inject
     private MojoAnnotationsScanner mojoAnnotationsScanner;
 
@@ -141,6 +180,18 @@ public class JavaAnnotationsMojoDescriptorExtractor
     {
         Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = scanAnnotations( request );
 
+        Optional<Short> requiredJavaVersion = mojoAnnotatedClasses.values().stream()
+                        .map( MojoAnnotatedClass::getClassVersion ).max( Short::compare );
+        if ( requiredJavaVersion.isPresent() )
+        {
+            String requiredJavaVersionString = MAJOR_CLASS_VERSION_TO_JAVA_STRING.get( requiredJavaVersion.get() );
+            if ( StringUtils.isBlank( request.getRequiredJavaVersion() )
+                                      || new ComparableVersion( request.getRequiredJavaVersion() ).compareTo( 
+                                             new ComparableVersion( requiredJavaVersionString ) ) < 0 )
+            {
+                request.setRequiredJavaVersion( requiredJavaVersionString );
+            }
+        }
         JavaProjectBuilder builder = scanJavadoc( request, mojoAnnotatedClasses.values() );
         Map<String, JavaClass> javaClassesMap = discoverClasses( builder );
 
@@ -175,7 +226,9 @@ public class JavaAnnotationsMojoDescriptorExtractor
 
         mojoAnnotationsScannerRequest.setProject( request.getProject() );
 
-        return mojoAnnotationsScanner.scan( mojoAnnotationsScannerRequest );
+        Map<String, MojoAnnotatedClass> result = mojoAnnotationsScanner.scan( mojoAnnotationsScannerRequest );
+        request.setUsedMavenApiVersion( mojoAnnotationsScannerRequest.getMavenApiVersion() );
+        return result;
     }
 
     private JavaProjectBuilder scanJavadoc( PluginToolsRequest request,
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 b681f8ec..f559ea83 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
@@ -22,6 +22,20 @@ package org.apache.maven.tools.plugin.extractor.annotations.scanner;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.Execute;
@@ -44,18 +58,6 @@ import org.codehaus.plexus.util.reflection.ReflectorException;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.Type;
 
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
 /**
  * Mojo scanner with java annotations.
  *
@@ -85,12 +87,18 @@ public class DefaultMojoAnnotationsScanner
             for ( Artifact dependency : request.getDependencies() )
             {
                 scan( mojoAnnotatedClasses, dependency.getFile(), request.getIncludePatterns(), dependency, true );
+                if ( request.getMavenApiVersion() == null
+                     && dependency.getFile().getName().contains( "maven-plugin-api" ) )
+                {
+                    request.setMavenApiVersion( getSpecificationVersionOfJar( dependency.getFile() ) );
+                }
             }
 
             for ( File classDirectory : request.getClassesDirectories() )
             {
                 scan( mojoAnnotatedClasses, classDirectory, request.getIncludePatterns(),
                       request.getProject().getArtifact(), false );
+                
             }
         }
         catch ( IOException e )
@@ -123,6 +131,15 @@ public class DefaultMojoAnnotationsScanner
         mojoAnnotatedClasses.putAll( scanResult );
     }
 
+    private String getSpecificationVersionOfJar( File file ) throws IOException
+    {
+        try ( JarFile jarFile = new JarFile( file ) )
+        {
+            // https://maven.apache.org/shared/maven-archiver/examples/manifest.html
+            return jarFile.getManifest().getMainAttributes().getValue( Attributes.Name.SPECIFICATION_VERSION );
+        }
+    }
+
     /**
      * @param archiveFile
      * @param artifact
@@ -210,10 +227,11 @@ public class DefaultMojoAnnotationsScanner
         throws IOException, ExtractionException
     {
         MojoClassVisitor mojoClassVisitor = new MojoClassVisitor( );
-
+        short classVersion;
         try
         {
             ClassReader rdr = new ClassReader( is );
+            classVersion = rdr.readShort( 6 );
             rdr.accept( mojoClassVisitor, ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG );
         }
         catch ( ArrayIndexOutOfBoundsException aiooe )
@@ -254,6 +272,7 @@ public class DefaultMojoAnnotationsScanner
             }
             mojoAnnotatedClass.setArtifact( artifact );
             mojoAnnotatedClasses.put( mojoAnnotatedClass.getClassName(), mojoAnnotatedClass );
+            mojoAnnotatedClass.setClassVersion( classVersion );
         }
     }
 
diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotatedClass.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotatedClass.java
index ab5f5b15..0776a90f 100644
--- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotatedClass.java
+++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotatedClass.java
@@ -19,15 +19,15 @@ package org.apache.maven.tools.plugin.extractor.annotations.scanner;
  * under the License.
  */
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ComponentAnnotationContent;
 import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ExecuteAnnotationContent;
 import org.apache.maven.tools.plugin.extractor.annotations.datamodel.MojoAnnotationContent;
 import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ParameterAnnotationContent;
 
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * @author Olivier Lamy
  * @since 3.0
@@ -36,6 +36,8 @@ public class MojoAnnotatedClass
 {
     private String className;
 
+    private short classVersion;
+
     private String parentClassName;
 
     private MojoAnnotationContent mojo;
@@ -73,6 +75,17 @@ public class MojoAnnotatedClass
         return this;
     }
 
+    public short getClassVersion()
+    {
+        return classVersion;
+    }
+
+    public MojoAnnotatedClass setClassVersion( short classVersion )
+    {
+        this.classVersion = classVersion;
+        return this;
+    }
+
     public MojoAnnotationContent getMojo()
     {
         return mojo;
@@ -157,6 +170,7 @@ public class MojoAnnotatedClass
         final StringBuilder sb = new StringBuilder();
         sb.append( "MojoAnnotatedClass" );
         sb.append( "{className='" ).append( className ).append( '\'' );
+        sb.append( ", classVersion=" ).append( classVersion );
         sb.append( ", parentClassName='" ).append( parentClassName ).append( '\'' );
         sb.append( ", mojo=" ).append( mojo );
         sb.append( ", execute=" ).append( execute );
@@ -165,4 +179,5 @@ public class MojoAnnotatedClass
         sb.append( '}' );
         return sb.toString();
     }
+
 }
diff --git a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotationsScannerRequest.java b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotationsScannerRequest.java
index 5a27cbd5..55611eeb 100644
--- a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotationsScannerRequest.java
+++ b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/MojoAnnotationsScannerRequest.java
@@ -45,6 +45,8 @@ public class MojoAnnotationsScannerRequest
 
     private MavenProject project;
 
+    private String mavenApiVersion;
+
     public MojoAnnotationsScannerRequest()
     {
         // no o
@@ -99,4 +101,14 @@ public class MojoAnnotationsScannerRequest
     {
         this.project = project;
     }
+
+    public String getMavenApiVersion()
+    {
+        return mavenApiVersion;
+    }
+
+    public void setMavenApiVersion( String mavenApiVersion )
+    {
+        this.mavenApiVersion = mavenApiVersion;
+    }
 }
diff --git a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/DefaultPluginToolsRequest.java b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/DefaultPluginToolsRequest.java
index f7b937ea..d3d4d352 100644
--- a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/DefaultPluginToolsRequest.java
+++ b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/DefaultPluginToolsRequest.java
@@ -61,13 +61,17 @@ public class DefaultPluginToolsRequest
     private ArtifactRepository local;
 
     private URI internalJavadocBaseUrl;
-    
+
     private String internalJavadocVersion;
-    
+
     private List<URI> externalJavadocBaseUrls;
 
     private Settings settings;
 
+    private String requiredJavaVersion;
+
+    private String mavenApiVersion;
+
     public DefaultPluginToolsRequest( MavenProject project, PluginDescriptor pluginDescriptor )
     {
         this.project = project;
@@ -252,4 +256,32 @@ public class DefaultPluginToolsRequest
     {
         return settings;
     }
+
+    @Override
+    public PluginToolsRequest setRequiredJavaVersion( String requiredJavaVersion )
+    {
+        this.requiredJavaVersion = requiredJavaVersion;
+        return this;
+    }
+    
+    @Override
+    public String getRequiredJavaVersion()
+    {
+        return requiredJavaVersion;
+    }
+
+    @Override
+    public PluginToolsRequest setUsedMavenApiVersion( String mavenApiVersion )
+    {
+        this.mavenApiVersion = mavenApiVersion;
+        return this;
+    }
+
+    @Override
+    public String getUsedMavenApiVersion()
+    {
+        return mavenApiVersion;
+    }
+
+    
 }
diff --git a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedMojoDescriptor.java b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedMojoDescriptor.java
index 7a54c456..0ab5b439 100644
--- a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedMojoDescriptor.java
+++ b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedMojoDescriptor.java
@@ -19,11 +19,14 @@ package org.apache.maven.tools.plugin;
  * under the License.
  */
 
+import java.util.Objects;
+
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.Parameter;
 
 /**
- * Extensions to MojoDescriptor added to Maven 3, then are not available when run under Maven2.
+ * Extensions to {@link MojoDescriptor} not supported by Maven 3.2.5.
+ * 
  * @author Kristian Rosenvold
  */
 public class ExtendedMojoDescriptor
@@ -31,10 +34,6 @@ public class ExtendedMojoDescriptor
 {
     private final boolean containsXhtmlTextValues;
 
-    private boolean threadSafe = false;
-
-    private String requiresDependencyCollection = null;
-
     public ExtendedMojoDescriptor()
     {
         this( false );
@@ -49,30 +48,6 @@ public class ExtendedMojoDescriptor
         this.containsXhtmlTextValues = containsXhtmlTextValues;
     }
 
-    @Override
-    public boolean isThreadSafe()
-    {
-        return threadSafe;
-    }
-
-    @Override
-    public void setThreadSafe( boolean threadSafe )
-    {
-        this.threadSafe = threadSafe;
-    }
-
-    @Override
-    public String getDependencyCollectionRequired()
-    {
-        return requiresDependencyCollection;
-    }
-
-    @Override
-    public void setDependencyCollectionRequired( String requiresDependencyCollection )
-    {
-        this.requiresDependencyCollection = requiresDependencyCollection;
-    }
-    
     /**
      * Indicates if the methods {@link #getDescription()}, {@link #getDeprecated()}, {@link Parameter#getDescription()}
      * and {@link Parameter#getDeprecated()} return XHTML values.
@@ -84,4 +59,32 @@ public class ExtendedMojoDescriptor
     {
         return containsXhtmlTextValues;
     }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + Objects.hash( containsXhtmlTextValues );
+        return result;
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        ExtendedMojoDescriptor other = (ExtendedMojoDescriptor) obj;
+        return containsXhtmlTextValues == other.containsXhtmlTextValues;
+    }
 }
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
new file mode 100644
index 00000000..f2f8c2d9
--- /dev/null
+++ b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/ExtendedPluginDescriptor.java
@@ -0,0 +1,282 @@
+package org.apache.maven.tools.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.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.model.Plugin;
+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.
+ * This is a wrapper around an existing PluginDescriptor.
+ */
+public class ExtendedPluginDescriptor extends PluginDescriptor
+{
+    private final PluginDescriptor delegate;
+    private String requiredJavaVersion;
+
+    public ExtendedPluginDescriptor( PluginDescriptor delegate )
+    {
+        this.delegate = delegate;
+        // populate the fields feeding the final methods of ComponentSetDescriptor 
+        // which can't be overridden by this wrapper
+        this.setIsolatedRealm( delegate.isIsolatedRealm() );
+        this.setDependencies( delegate.getDependencies() );
+        this.setComponents( delegate.getComponents() );
+    }
+
+    public void setRequiredJavaVersion( String requiredJavaVersion )
+    {
+        this.requiredJavaVersion = requiredJavaVersion;
+    }
+
+    public String getRequiredJavaVersion()
+    {
+        return requiredJavaVersion;
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        ExtendedPluginDescriptor other = (ExtendedPluginDescriptor) obj;
+        return Objects.equals( delegate, other.delegate )
+            && Objects.equals( requiredJavaVersion, other.requiredJavaVersion );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + Objects.hash( delegate, requiredJavaVersion );
+        return result;
+    }
+
+    /* -- START delegate methods --*/
+    public List<MojoDescriptor> getMojos()
+    {
+        return delegate.getMojos();
+    }
+
+    public void addMojo( MojoDescriptor mojoDescriptor )
+        throws DuplicateMojoDescriptorException
+    {
+        delegate.addMojo( mojoDescriptor );
+    }
+
+    public String getGroupId()
+    {
+        return delegate.getGroupId();
+    }
+
+    public void setGroupId( String groupId )
+    {
+        delegate.setGroupId( groupId );
+    }
+
+    public String getArtifactId()
+    {
+        return delegate.getArtifactId();
+    }
+
+    public void setArtifactId( String artifactId )
+    {
+        delegate.setArtifactId( artifactId );
+    }
+
+    public String getPluginLookupKey()
+    {
+        return delegate.getPluginLookupKey();
+    }
+
+    public String getId()
+    {
+        return delegate.getId();
+    }
+
+    public String getGoalPrefix()
+    {
+        return delegate.getGoalPrefix();
+    }
+
+    public void setGoalPrefix( String goalPrefix )
+    {
+        delegate.setGoalPrefix( goalPrefix );
+    }
+
+    public void setVersion( String version )
+    {
+        delegate.setVersion( version );
+    }
+
+    public String getVersion()
+    {
+        return delegate.getVersion();
+    }
+
+    public void setSource( String source )
+    {
+        delegate.setSource( source );
+    }
+
+    public String getSource()
+    {
+        return delegate.getSource();
+    }
+
+    public boolean isInheritedByDefault()
+    {
+        return delegate.isInheritedByDefault();
+    }
+
+    public void setInheritedByDefault( boolean inheritedByDefault )
+    {
+        delegate.setInheritedByDefault( inheritedByDefault );
+    }
+
+    public List<Artifact> getArtifacts()
+    {
+        return delegate.getArtifacts();
+    }
+
+    public void setArtifacts( List<Artifact> artifacts )
+    {
+        delegate.setArtifacts( artifacts );
+    }
+
+    public Map<String, Artifact> getArtifactMap()
+    {
+        return delegate.getArtifactMap();
+    }
+
+    public MojoDescriptor getMojo( String goal )
+    {
+        return delegate.getMojo( goal );
+    }
+
+    public void setClassRealm( ClassRealm classRealm )
+    {
+        delegate.setClassRealm( classRealm );
+    }
+
+    public ClassRealm getClassRealm()
+    {
+        return delegate.getClassRealm();
+    }
+
+    public void setIntroducedDependencyArtifacts( Set<Artifact> introducedDependencyArtifacts )
+    {
+        delegate.setIntroducedDependencyArtifacts( introducedDependencyArtifacts );
+    }
+
+    public Set<Artifact> getIntroducedDependencyArtifacts()
+    {
+        return delegate.getIntroducedDependencyArtifacts();
+    }
+
+    public void setName( String name )
+    {
+        delegate.setName( name );
+    }
+
+    public String getName()
+    {
+        return delegate.getName();
+    }
+
+    public void setDescription( String description )
+    {
+        delegate.setDescription( description );
+    }
+
+    public String getDescription()
+    {
+        return delegate.getDescription();
+    }
+
+    public void setRequiredMavenVersion( String requiredMavenVersion )
+    {
+        delegate.setRequiredMavenVersion( requiredMavenVersion );
+    }
+
+    public String getRequiredMavenVersion()
+    {
+        return delegate.getRequiredMavenVersion();
+    }
+
+    public void setPlugin( Plugin plugin )
+    {
+        delegate.setPlugin( plugin );
+    }
+
+    @Override
+    public Plugin getPlugin()
+    {
+        return delegate.getPlugin();
+    }
+
+    @Override
+    public Artifact getPluginArtifact()
+    {
+        return delegate.getPluginArtifact();
+    }
+
+    @Override
+    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-api/src/main/java/org/apache/maven/tools/plugin/PluginToolsRequest.java b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/PluginToolsRequest.java
index 9f740be7..a0721e80 100644
--- a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/PluginToolsRequest.java
+++ b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/PluginToolsRequest.java
@@ -197,4 +197,34 @@ public interface PluginToolsRequest
      * @since 3.7.0
      */
     Settings getSettings();
+    
+    /**
+     * 
+     * @param requiredJavaVersion the required java version for this plugin or {@code null} if unknown.
+     * @return This request.
+     * @since 3.8.0
+     */
+    PluginToolsRequest setRequiredJavaVersion( String requiredJavaVersion );
+
+    /**
+     * 
+     * @return the required java version for this plugin or {@code null} if unknown.
+     * @since 3.8.0
+     */
+    String getRequiredJavaVersion();
+
+    /**
+     * 
+     * @param mavenApiVersion
+     * @return his request.
+     * @since 3.8.0
+     */
+    PluginToolsRequest setUsedMavenApiVersion( String mavenApiVersion );
+
+    /**
+     * 
+     * @return the Maven API version being referenced or {@code null} if unknown
+     * @since 3.8.0
+     */
+    String getUsedMavenApiVersion();
 }
diff --git a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/extractor/MojoDescriptorExtractor.java b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/extractor/MojoDescriptorExtractor.java
index cbac0d5a..b9eef688 100644
--- a/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/extractor/MojoDescriptorExtractor.java
+++ b/maven-plugin-tools-api/src/main/java/org/apache/maven/tools/plugin/extractor/MojoDescriptorExtractor.java
@@ -33,14 +33,14 @@ public interface MojoDescriptorExtractor
     /**
      * Returns the "name" (id) of the extractor.
      *
-     * @since TBD
+     * @since 3.7.0
      */
     String getName();
 
     /**
      * Returns {@code true} if extractor is deprecated.
      *
-     * @since TBD
+     * @since 3.7.0
      */
     boolean isDeprecated();
 
@@ -48,7 +48,7 @@ public interface MojoDescriptorExtractor
      * Returns the {@link GroupKey} of extractor, as {@link org.apache.maven.tools.plugin.scanner.MojoScanner} will
      * execute them grouped, and ordered within groups. Must never return {@code null}.
      *
-     * @since TBD
+     * @since 3.7.0
      */
     GroupKey getGroupKey();
 
@@ -63,4 +63,15 @@ public interface MojoDescriptorExtractor
      */
     List<MojoDescriptor> execute( PluginToolsRequest request )
         throws ExtractionException, InvalidPluginDescriptorException;
+
+    /**
+     * The default implementation returns {@code null}.
+     * @return the required java version or {@code null} if unknown
+     *
+     * @since 3.8.0
+     */
+    default String getRequiredJavaVersion()
+    {
+        return null;
+    }
 }
\ No newline at end of file
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 cce415f0..493a1eba 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
@@ -36,6 +36,7 @@ import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.apache.maven.plugin.descriptor.Requirement;
 import org.apache.maven.project.MavenProject;
 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.javadoc.JavadocLinkGenerator;
 import org.apache.maven.tools.plugin.util.PluginUtils;
@@ -163,6 +164,20 @@ public class PluginDescriptorFilesGenerator
 
                 GeneratorUtils.element( w, "inheritedByDefault",
                                         String.valueOf( pluginDescriptor.isInheritedByDefault() ) );
+
+                if ( pluginDescriptor instanceof ExtendedPluginDescriptor )
+                {
+                    ExtendedPluginDescriptor extPluginDescriptor = (ExtendedPluginDescriptor) pluginDescriptor;
+                    if ( StringUtils.isNotBlank( extPluginDescriptor.getRequiredJavaVersion() ) )
+                    {
+                        GeneratorUtils.element( w, "requiredJavaVersion", 
+                                                extPluginDescriptor.getRequiredJavaVersion() );
+                    }
+                }
+                if ( StringUtils.isNotBlank( pluginDescriptor.getRequiredMavenVersion() ) )
+                {
+                    GeneratorUtils.element( w, "requiredMavenVersion", pluginDescriptor.getRequiredMavenVersion() );
+                }
             }
 
             w.startElement( "mojos" );