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

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


The following commit(s) were added to refs/heads/master by this push:
     new a0ec0ba3 [MPLUGIN-427] Expose generics information of parameter types 
in report (#159)
a0ec0ba3 is described below

commit a0ec0ba3f27804ec849344adaa96a9277628724a
Author: Konrad Windszus <[email protected]>
AuthorDate: Wed Oct 26 15:59:02 2022 +0200

    [MPLUGIN-427] Expose generics information of parameter types in report 
(#159)
---
 maven-plugin-tools-annotations/pom.xml             |   4 +
 .../JavaAnnotationsMojoDescriptorExtractor.java    |   9 +-
 .../datamodel/ParameterAnnotationContent.java      |  25 ++++-
 .../scanner/DefaultMojoAnnotationsScanner.java     |   3 +-
 .../scanner/visitors/MojoClassVisitor.java         |  47 +++++++++-
 .../scanner/visitors/MojoFieldVisitor.java         |  12 ++-
 .../scanner/visitors/MojoMethodVisitor.java        |  12 ++-
 .../scanner/visitors/MojoParameterVisitor.java     |   3 +
 .../annotations/ParametersWithGenericsMojo.java    |  66 +++++++++++++
 .../annotations/TestAnnotationsReader.java         |  12 +--
 .../scanner/DefaultMojoAnnotationsScannerTest.java |  48 ++++++++++
 .../generator/PluginDescriptorFilesGenerator.java  | 102 ++++++++++++++++-----
 .../plugin/generator/PluginXdocGenerator.java      |  60 +++++++++++-
 .../PluginDescriptorFilesGeneratorTest.java        |  35 +++++--
 .../plugin/generator/PluginXdocGeneratorTest.java  |  11 +++
 pom.xml                                            |   6 +-
 16 files changed, 399 insertions(+), 56 deletions(-)

diff --git a/maven-plugin-tools-annotations/pom.xml 
b/maven-plugin-tools-annotations/pom.xml
index 52e9f3b4..1830d669 100644
--- a/maven-plugin-tools-annotations/pom.xml
+++ b/maven-plugin-tools-annotations/pom.xml
@@ -78,6 +78,10 @@
       <groupId>org.ow2.asm</groupId>
       <artifactId>asm</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.ow2.asm</groupId>
+      <artifactId>asm-util</artifactId>
+    </dependency>
     <!-- for HTML to plain text conversion -->
     <dependency>
       <groupId>org.jsoup</groupId>
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 d3704293..ac7b4ea9 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
@@ -39,6 +39,7 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
+import java.util.stream.Collectors;
 
 import com.thoughtworks.qdox.JavaProjectBuilder;
 import com.thoughtworks.qdox.library.SortedClassLibraryBuilder;
@@ -698,7 +699,13 @@ public class JavaAnnotationsMojoDescriptorExtractor
                             + property, null );
                 }
                 parameter.setExpression( StringUtils.isEmpty( property ) ? "" 
: "${" + property + "}" );
-                parameter.setType( parameterAnnotationContent.getClassName() );
+                StringBuilder type = new StringBuilder( 
parameterAnnotationContent.getClassName() );
+                if ( !parameterAnnotationContent.getTypeParameters().isEmpty() 
)
+                {
+                    type.append( 
parameterAnnotationContent.getTypeParameters().stream()
+                            .collect( Collectors.joining( ", ", "<", ">" ) ) );
+                }
+                parameter.setType( type.toString() );
                 parameter.setSince( parameterAnnotationContent.getSince() );
                 parameter.setRequired( parameterAnnotationContent.required() );
 
diff --git 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ParameterAnnotationContent.java
 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ParameterAnnotationContent.java
index 3d9f8922..6ac23be5 100644
--- 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ParameterAnnotationContent.java
+++ 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ParameterAnnotationContent.java
@@ -23,6 +23,7 @@ import org.apache.maven.plugins.annotations.Parameter;
 import org.objectweb.asm.Type;
 
 import java.lang.annotation.Annotation;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -50,16 +51,20 @@ public class ParameterAnnotationContent
 
     private String className;
 
-    public ParameterAnnotationContent( String fieldName, String className )
+    private final List<String> typeParameters;
+
+    public ParameterAnnotationContent( String fieldName, String className, 
List<String> typeParameters )
     {
         super( fieldName );
         this.className = className;
+        this.typeParameters = typeParameters;
     }
 
     public ParameterAnnotationContent( String fieldName, String alias, String 
property, String defaultValue,
-                                       Class<?> implementation, boolean 
required, boolean readonly, String className )
+                                       Class<?> implementation, boolean 
required, boolean readonly, String className,
+                                       List<String> typeParameters )
     {
-        this( fieldName, className );
+        this( fieldName, className, typeParameters );
         this.alias = alias;
         this.property = property;
         this.defaultValue = defaultValue;
@@ -177,6 +182,11 @@ public class ParameterAnnotationContent
         this.className = className;
     }
 
+    public List<String> getTypeParameters()
+    {
+        return typeParameters;
+    }
+
     @Override
     public String toString()
     {
@@ -185,6 +195,7 @@ public class ParameterAnnotationContent
         sb.append( "ParameterAnnotationContent" );
         sb.append( "{fieldName='" ).append( getFieldName() ).append( '\'' );
         sb.append( ", className='" ).append( getClassName() ).append( '\'' );
+        sb.append( ", typeParameters='" ).append( getTypeParameters() 
).append( '\'' );
         sb.append( ", name='" ).append( name ).append( '\'' );
         sb.append( ", alias='" ).append( alias ).append( '\'' );
         sb.append( ", alias='" ).append( alias ).append( '\'' );
@@ -230,6 +241,10 @@ public class ParameterAnnotationContent
             return false;
         }
 
+        if ( !Objects.equals( typeParameters, that.typeParameters ) )
+        {
+            return false;
+        }
         if ( !Objects.equals( alias, that.alias ) )
         {
             return false;
@@ -253,7 +268,7 @@ public class ParameterAnnotationContent
     @Override
     public int hashCode()
     {
-        return Objects.hash( alias, getFieldName(), property, defaultValue, 
required, readonly,
-                             implementationClassName );
+        return Objects.hash( alias, getFieldName(), getClassName(), 
typeParameters, property, defaultValue, required,
+                             readonly, implementationClassName );
     }
 }
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 2b441751..c0e3ed88 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
@@ -302,7 +302,8 @@ public class DefaultMojoAnnotationsScanner
             for ( MojoParameterVisitor parameterVisitor : 
mojoParameterVisitors )
             {
                 ParameterAnnotationContent parameterAnnotationContent =
-                    new ParameterAnnotationContent( 
parameterVisitor.getFieldName(), parameterVisitor.getClassName() );
+                    new ParameterAnnotationContent( 
parameterVisitor.getFieldName(), parameterVisitor.getClassName(),
+                                                    
parameterVisitor.getTypeParameters() );
 
                 Map<String, MojoAnnotationVisitor> annotationVisitorMap = 
parameterVisitor.getAnnotationVisitorMap();
                 MojoAnnotationVisitor fieldAnnotationVisitor = 
annotationVisitorMap.get( Parameter.class.getName() );
diff --git 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoClassVisitor.java
 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoClassVisitor.java
index 9376564d..6267d64f 100644
--- 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoClassVisitor.java
+++ 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoClassVisitor.java
@@ -20,6 +20,8 @@ package 
org.apache.maven.tools.plugin.extractor.annotations.scanner.visitors;
  */
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -36,6 +38,8 @@ import org.objectweb.asm.FieldVisitor;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
+import org.objectweb.asm.signature.SignatureReader;
+import org.objectweb.asm.util.TraceSignatureVisitor;
 
 /**
  * Visitor for Mojo classes.
@@ -117,11 +121,49 @@ public class MojoClassVisitor
     @Override
     public FieldVisitor visitField( int access, String name, String desc, 
String signature, Object value )
     {
-        MojoFieldVisitor mojoFieldVisitor = new MojoFieldVisitor( name, 
Type.getType( desc ).getClassName() );
+        List<String> typeParameters = extractTypeParameters( access, 
signature, true );
+        MojoFieldVisitor mojoFieldVisitor = new MojoFieldVisitor( name, 
Type.getType( desc ).getClassName(),
+                typeParameters );
         fieldVisitors.add( mojoFieldVisitor );
         return mojoFieldVisitor;
     }
 
+    /**
+     * Parses the signature according to 
+     * <a 
href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.4";>JVMS
 4.3.4</a>
+     * and returns the type parameters.
+     * @param access
+     * @param signature
+     * @param isField
+     * @return the list of type parameters (may be empty)
+     */
+    private List<String> extractTypeParameters( int access, String signature, 
boolean isField )
+    {
+        if ( StringUtils.isEmpty( signature ) )
+        {
+            return Collections.emptyList();
+        }
+        TraceSignatureVisitor traceSignatureVisitor = new 
TraceSignatureVisitor( access );
+        SignatureReader signatureReader = new SignatureReader( signature );
+        if ( isField )
+        {
+            signatureReader.acceptType( traceSignatureVisitor );
+        }
+        else
+        {
+            signatureReader.accept( traceSignatureVisitor );
+        }
+        String declaration = traceSignatureVisitor.getDeclaration();
+        int startTypeParameters = declaration.indexOf( '<' );
+        if ( startTypeParameters == -1 )
+        {
+            return Collections.emptyList();
+        }
+        String typeParameters = declaration.substring( startTypeParameters + 1,
+                                                       
declaration.lastIndexOf( '>' ) );
+        return Arrays.asList( typeParameters.split( ", " ) );
+    }
+
     @Override
     public MethodVisitor visitMethod( int access, String name, String desc, 
String signature, String[] exceptions )
     {
@@ -142,8 +184,9 @@ public class MojoClassVisitor
         {
             String fieldName = StringUtils.lowercaseFirstLetter( 
name.substring( 3 ) );
             String className = type.getArgumentTypes()[0].getClassName();
+            List<String> typeParameters = extractTypeParameters( access, 
signature, false );
 
-            MojoMethodVisitor mojoMethodVisitor = new MojoMethodVisitor( 
fieldName, className );
+            MojoMethodVisitor mojoMethodVisitor = new MojoMethodVisitor( 
fieldName, className, typeParameters );
             methodVisitors.add( mojoMethodVisitor );
             return mojoMethodVisitor;
         }
diff --git 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoFieldVisitor.java
 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoFieldVisitor.java
index 550bd579..3e017afc 100644
--- 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoFieldVisitor.java
+++ 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoFieldVisitor.java
@@ -20,6 +20,7 @@ package 
org.apache.maven.tools.plugin.extractor.annotations.scanner.visitors;
  */
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import 
org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotationsScanner;
@@ -43,11 +44,14 @@ public class MojoFieldVisitor
 
     private String className;
 
-    MojoFieldVisitor( String fieldName, String className )
+    private final List<String> typeParameters;
+
+    MojoFieldVisitor( String fieldName, String className, List<String> 
typeParameters )
     {
         super( Opcodes.ASM9 );
         this.fieldName = fieldName;
         this.className = className;
+        this.typeParameters = typeParameters;
     }
 
     @Override
@@ -62,6 +66,12 @@ public class MojoFieldVisitor
         return fieldName;
     }
 
+    @Override
+    public List<String> getTypeParameters()
+    {
+        return typeParameters;
+    }
+
     @Override
     public AnnotationVisitor visitAnnotation( String desc, boolean visible )
     {
diff --git 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoMethodVisitor.java
 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoMethodVisitor.java
index 448bb788..dd121f72 100644
--- 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoMethodVisitor.java
+++ 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoMethodVisitor.java
@@ -20,6 +20,7 @@ package 
org.apache.maven.tools.plugin.extractor.annotations.scanner.visitors;
  */
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import 
org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotationsScanner;
@@ -37,14 +38,15 @@ public class MojoMethodVisitor extends MethodVisitor 
implements MojoParameterVis
 {
     private final String className;
     private final String fieldName;
-
+    private final List<String> typeParameters;
     private Map<String, MojoAnnotationVisitor> annotationVisitorMap = new 
HashMap<>();
 
-    public MojoMethodVisitor( String fieldName, String className )
+    public MojoMethodVisitor( String fieldName, String className, List<String> 
typeParameters )
     {
         super( Opcodes.ASM9 );
         this.fieldName = fieldName;
         this.className = className;
+        this.typeParameters = typeParameters;
     }
 
     @Override
@@ -73,6 +75,12 @@ public class MojoMethodVisitor extends MethodVisitor 
implements MojoParameterVis
         return className;
     }
 
+    @Override
+    public List<String> getTypeParameters()
+    {
+        return typeParameters;
+    }
+
     @Override
     public Map<String, MojoAnnotationVisitor> getAnnotationVisitorMap()
     {
diff --git 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoParameterVisitor.java
 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoParameterVisitor.java
index c95ac05c..e9ba4057 100644
--- 
a/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoParameterVisitor.java
+++ 
b/maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoParameterVisitor.java
@@ -19,6 +19,7 @@ package 
org.apache.maven.tools.plugin.extractor.annotations.scanner.visitors;
  * under the License.
  */
 
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -32,5 +33,7 @@ public interface MojoParameterVisitor
 
     String getClassName();
 
+    List<String> getTypeParameters();
+
     Map<String, MojoAnnotationVisitor> getAnnotationVisitorMap();
 }
diff --git 
a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java
 
b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java
new file mode 100644
index 00000000..5a1d3a26
--- /dev/null
+++ 
b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java
@@ -0,0 +1,66 @@
+package org.apache.maven.tools.plugin.extractor.annotations;
+
+/*
+ * 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.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+
+@Mojo( name = "parameter-with-generics" )
+public class ParametersWithGenericsMojo
+    extends AbstractMojo
+{
+
+    @Parameter
+    private String string;
+
+    @Parameter
+    private Map<String, Boolean> stringBooleanMap;
+    
+    @Parameter
+    private Collection<Integer> integerCollection;
+
+    @Parameter
+    private Collection<Collection<String>> nestedStringCollection;
+
+    @Parameter
+    private Collection<Integer[]> integerArrayCollection;
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+    }
+
+    @Parameter( name="numberList" )
+    public void setNumberList(List<Number> numberList) {
+    }
+
+    public static class NestedClass<E extends Number> {
+        /**
+         * Some field without type parameter but non-empty signature
+         */
+        protected E filter;
+    }
+}
\ No newline at end of file
diff --git 
a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/TestAnnotationsReader.java
 
b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/TestAnnotationsReader.java
index 81796881..dca5896c 100644
--- 
a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/TestAnnotationsReader.java
+++ 
b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/TestAnnotationsReader.java
@@ -98,25 +98,25 @@ class TestAnnotationsReader
             .hasSize( 6 )
             .containsExactlyInAnyOrder(
                 new ParameterAnnotationContent( "bar", null, "thebar", 
"coolbar", null, true, false,
-                                                String.class.getName() ),
+                                                String.class.getName(), 
Collections.emptyList() ),
                 new ParameterAnnotationContent( "beer", null, "thebeer", 
"coolbeer", null, false, false,
-                                                String.class.getName() ),
+                                                String.class.getName(), 
Collections.emptyList() ),
                 new ParameterAnnotationContent( "fooInterface", null, 
"fooInterface", null,
                                                 FooInterfaceImpl.class,
                                                 false,
-                                                false, 
FooInterface.class.getName() ),
+                                                false, 
FooInterface.class.getName(), Collections.emptyList() ),
                 new ParameterAnnotationContent( "paramFromSetter", null, 
"props.paramFromSetter", null,
                                                 null,
                                                 false,
-                                                false, String.class.getName() 
),
+                                                false, String.class.getName(), 
Collections.emptyList() ),
                 new ParameterAnnotationContent( "paramFromAdd", null, 
"props.paramFromAdd", null,
                                                 null,
                                                 false,
-                                                false, String.class.getName() 
),
+                                                false, String.class.getName(), 
Collections.emptyList() ),
                 new ParameterAnnotationContent( "paramFromSetterDeprecated", 
null, "props.paramFromSetterDeprecated", null,
                                                 null,
                                                 false,
-                                                false, List.class.getName() )
+                                                false, List.class.getName(), 
Collections.singletonList("java.lang.String") )
             );
     }
 }
diff --git 
a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java
 
b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java
index 87dfc4e5..9c8f0b8d 100644
--- 
a/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java
+++ 
b/maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScannerTest.java
@@ -26,10 +26,14 @@ import java.util.Map;
 
 import org.apache.maven.tools.plugin.extractor.ExtractionException;
 import org.apache.maven.tools.plugin.extractor.annotations.DeprecatedMojo;
+import 
org.apache.maven.tools.plugin.extractor.annotations.ParametersWithGenericsMojo;
+import 
org.apache.maven.tools.plugin.extractor.annotations.datamodel.ParameterAnnotationContent;
 import org.codehaus.plexus.logging.Logger;
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.mockito.Mockito.mock;
 
 class DefaultMojoAnnotationsScannerTest
@@ -76,4 +80,48 @@ class DefaultMojoAnnotationsScannerTest
             .isEqualTo( "property.anotherNotDeprecated" );
     }
 
+    @Test
+    void scanParametersWithGenerics() throws ExtractionException, IOException
+    {
+        File directoryToScan = new File( 
ParametersWithGenericsMojo.class.getResource( "" ).getFile() );
+
+        scanner.enableLogging( mock( Logger.class ) );
+        Map<String, MojoAnnotatedClass> result = scanner.scanDirectory(
+            directoryToScan, Collections.singletonList( 
"ParametersWithGenericsMojo**.class" ), null, false );
+
+        assertThat( result ).hasSize( 2 ); // mojo and nested class
+
+        MojoAnnotatedClass annotatedClass = result.get( 
ParametersWithGenericsMojo.class.getName() );
+        assertThat( annotatedClass.getClassName() ).isEqualTo( 
ParametersWithGenericsMojo.class.getName() );
+
+        ParameterAnnotationContent parameter = 
annotatedClass.getParameters().get( "string" );
+        assertNotNull( parameter );
+        assertEquals( "java.lang.String", parameter.getClassName() );
+        assertThat( parameter.getTypeParameters() ).isEmpty();
+
+        parameter = annotatedClass.getParameters().get( "stringBooleanMap" );
+        assertNotNull( parameter );
+        assertEquals( "java.util.Map", parameter.getClassName() );
+        assertThat( parameter.getTypeParameters() ).containsExactly( 
"java.lang.String", "java.lang.Boolean" );
+
+        parameter = annotatedClass.getParameters().get( "integerCollection" );
+        assertNotNull( parameter );
+        assertEquals( "java.util.Collection", parameter.getClassName() );
+        assertThat( parameter.getTypeParameters() ).containsExactly( 
"java.lang.Integer" );
+
+        parameter = annotatedClass.getParameters().get( 
"nestedStringCollection" );
+        assertNotNull( parameter );
+        assertEquals( "java.util.Collection", parameter.getClassName() );
+        assertThat( parameter.getTypeParameters() ).containsExactly( 
"java.util.Collection<java.lang.String>" );
+
+        parameter = annotatedClass.getParameters().get( 
"integerArrayCollection" );
+        assertNotNull( parameter );
+        assertEquals( "java.util.Collection", parameter.getClassName() );
+        assertThat( parameter.getTypeParameters() ).containsExactly( 
"java.lang.Integer[]" );
+
+        parameter = annotatedClass.getParameters().get( "numberList" );
+        assertNotNull( parameter );
+        assertEquals( "java.util.List", parameter.getClassName() );
+        assertThat( parameter.getTypeParameters() ).containsExactly( 
"java.lang.Number" );
+    }
 }
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 1f0f00c8..a21a4e44 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
@@ -511,31 +511,8 @@ public class PluginDescriptorFilesGenerator
                         GeneratorUtils.element( w, "alias", 
parameter.getAlias() );
                     }
 
-                    GeneratorUtils.element( w, "type", parameter.getType() );
+                    writeParameterType( w, type, javadocLinkGenerator, 
parameter, mojoDescriptor.getGoal() );
 
-                    if ( type == DescriptorType.XHTML && javadocLinkGenerator 
!= null )
-                    {
-                        // skip primitives which never has javadoc
-                        if ( parameter.getType().indexOf( '.' ) == -1 )
-                        {
-                            LOG.debug( "Javadoc URLs are not available for 
primitive types like {}",
-                                       parameter.getType() );
-                        }
-                        else
-                        {
-                            try
-                            {
-                                URI uri = javadocLinkGenerator.createLink( 
parameter.getType() );
-                                GeneratorUtils.element( w, "typeJavadocUrl", 
uri.toString() );
-                            } 
-                            catch ( IllegalArgumentException e )
-                            {
-                                LOG.warn( "Could not get javadoc URL for type 
{} of parameter {} from goal {}: {}",
-                                          parameter.getType(), 
parameter.getName(), mojoDescriptor.getGoal(),
-                                          e.getMessage() );
-                            }
-                        }
-                    }
                     if ( parameter.getSince() != null )
                     {
                         w.startElement( "since" );
@@ -665,6 +642,83 @@ public class PluginDescriptorFilesGenerator
         w.endElement();
     }
 
+    /**
+     * Writes parameter type information and potentially also the related 
javadoc URL.
+     * @param w
+     * @param type
+     * @param javadocLinkGenerator
+     * @param parameter
+     * @param goal
+     */
+    protected void writeParameterType( XMLWriter w, DescriptorType type, 
JavadocLinkGenerator javadocLinkGenerator,
+                                       Parameter parameter, String goal )
+    {
+        String parameterType = parameter.getType();
+        
+        if ( type == DescriptorType.STANDARD )
+        {
+            // strip type by parameter type (generics) information for 
standard plugin descriptor
+            parameterType = StringUtils.chomp( parameterType, "<" );
+        }
+        GeneratorUtils.element( w, "type", parameterType );
+
+        if ( type == DescriptorType.XHTML && javadocLinkGenerator != null )
+        {
+            // skip primitives which never has javadoc
+            if ( parameter.getType().indexOf( '.' ) == -1 )
+            {
+                LOG.debug( "Javadoc URLs are not available for primitive types 
like {}",
+                           parameter.getType() );
+            }
+            else
+            {
+                try
+                {
+                    URI javadocUrl = getJavadocUrlForType( 
javadocLinkGenerator, parameterType );
+                    GeneratorUtils.element( w, "typeJavadocUrl", 
javadocUrl.toString() );
+                } 
+                catch ( IllegalArgumentException e )
+                {
+                    LOG.warn( "Could not get javadoc URL for type {} of 
parameter {} from goal {}: {}",
+                              parameter.getType(), parameter.getName(), goal,
+                              e.getMessage() );
+                }
+            }
+        }
+    }
+
+    static URI getJavadocUrlForType( JavadocLinkGenerator 
javadocLinkGenerator, String type )
+    {
+        final String binaryName;
+        int startOfParameterType = type.indexOf( "<" );
+        if ( startOfParameterType != -1 )
+        {
+            // parse parameter type
+            String mainType = type.substring( 0, startOfParameterType );
+            
+            // some heuristics here
+            String[] parameterTypes = type.substring( startOfParameterType + 
1, type.lastIndexOf( ">" ) )
+                            .split( ",\\s*" );
+            switch ( parameterTypes.length )
+            {
+                case 1: // if only one parameter type, assume collection, 
first parameter type is most interesting
+                    binaryName = parameterTypes[0];
+                    break;
+                case 2: // if two parameter types assume map, second parameter 
type is most interesting
+                    binaryName = parameterTypes[1];
+                    break;
+                default:
+                    // all other cases link to main type
+                    binaryName = mainType;
+            }
+        }
+        else
+        {
+            binaryName = type;
+        }
+        return javadocLinkGenerator.createLink( binaryName );
+    }
+
     /**
      * Get the expression value, eventually surrounding it with <code>${ 
}</code>.
      *
diff --git 
a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
 
b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
index 9344cae8..c13a1790 100644
--- 
a/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
+++ 
b/maven-plugin-tools-generators/src/main/java/org/apache/maven/tools/plugin/generator/PluginXdocGenerator.java
@@ -546,13 +546,63 @@ public class PluginXdocGenerator
         w.endElement();
     }
 
+    static String getShortType( String type )
+    {
+        // split into type arguments and main type
+        int startTypeArguments = type.indexOf( '<' );
+        if ( startTypeArguments == -1 )
+        {
+            return getShortTypeOfSimpleType( type );
+        }
+        else
+        {
+            StringBuilder shortType = new StringBuilder();
+            shortType.append( getShortTypeOfSimpleType( type.substring( 0, 
startTypeArguments ) ) );
+            shortType.append( "<" )
+                .append( getShortTypeOfTypeArgument( 
+                        type.substring( startTypeArguments + 1, 
type.lastIndexOf( ">" ) ) ) )
+                .append( ">" );
+            return shortType.toString();
+        }
+        
+    }
+
+    private static String getShortTypeOfTypeArgument( String type )
+    {
+        String[] typeArguments = type.split( ",\\s*" );
+        StringBuilder shortType = new StringBuilder();
+        for ( int i = 0; i < typeArguments.length; i++ )
+        {
+            String typeArgument = typeArguments[i];
+            if ( typeArgument.contains( "<" ) )
+            {
+                // nested type arguments lead to ellipsis
+                return "...";
+            }
+            else
+            {
+                shortType.append( getShortTypeOfSimpleType( typeArgument ) );
+                if ( i < typeArguments.length - 1 )
+                {
+                    shortType.append( "," );
+                }
+            }
+        }
+        return shortType.toString();
+    }
+
+    private static String getShortTypeOfSimpleType( String type )
+    {
+        int index = type.lastIndexOf( '.' );
+        return type.substring( index + 1 );
+    }
+
     private String getLinkedType( Parameter parameter, boolean isShortType  )
     {
         final String typeValue;
         if ( isShortType )
         {
-            int index = parameter.getType().lastIndexOf( '.' );
-            typeValue = parameter.getType().substring( index + 1 );
+            typeValue = getShortType( parameter.getType() );
         }
         else
         {
@@ -568,12 +618,12 @@ public class PluginXdocGenerator
                 if ( javadocUrl.isAbsolute() 
                      || JavadocLinkGenerator.isLinkValid( javadocUrl, 
reportOutputDirectory.toPath() ) )
                 {
-                    return format( 
"pluginxdoc.mojodescriptor.parameter.type_link", 
-                                        new Object[] { typeValue, 
enhancedParameter.getTypeJavadocUrl() } );
+                    return format( 
"pluginxdoc.mojodescriptor.parameter.type_link",
+                                   new Object[] { escapeXml( typeValue ), 
enhancedParameter.getTypeJavadocUrl() } );
                 }
             }
         }
-        return typeValue;
+        return escapeXml( typeValue );
     }
 
     private boolean addUl( XMLWriter w, boolean addedUl, String content )
diff --git 
a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java
 
b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java
index 0187af03..3e8decd8 100644
--- 
a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java
+++ 
b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginDescriptorFilesGeneratorTest.java
@@ -19,22 +19,26 @@ package org.apache.maven.tools.plugin.generator;
  * under the License.
  */
 
-import org.apache.maven.plugin.descriptor.MojoDescriptor;
-import org.apache.maven.plugin.descriptor.Parameter;
-import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
-import org.codehaus.plexus.component.repository.ComponentDependency;
-import org.codehaus.plexus.testing.PlexusTest;
-import org.codehaus.plexus.util.ReaderFactory;
-
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.List;
 
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
+import org.apache.maven.tools.plugin.javadoc.JavadocLinkGenerator;
+import org.codehaus.plexus.component.repository.ComponentDependency;
+import org.codehaus.plexus.testing.PlexusTest;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.junit.jupiter.api.Test;
+
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -131,4 +135,19 @@ public class PluginDescriptorFilesGeneratorTest
 
         assertEquals( version, dependency.getVersion() );
     }
+
+    @Test
+    void testGetJavadocUrlForType() throws URISyntaxException
+    {
+        URI javadocBaseUri = new URI( "http://localhost/apidocs/"; );
+        JavadocLinkGenerator linkGenerator = new JavadocLinkGenerator( 
javadocBaseUri, "1.8" );
+        assertEquals( javadocBaseUri.resolve("java/lang/String.html"),
+                      PluginDescriptorFilesGenerator.getJavadocUrlForType( 
linkGenerator, "java.lang.String" ) );
+        assertEquals( javadocBaseUri.resolve("java/lang/String.html"),
+                      PluginDescriptorFilesGenerator.getJavadocUrlForType( 
linkGenerator, "java.lang.Collection<java.lang.String>" ) );
+        assertEquals( javadocBaseUri.resolve("java/lang/Integer.html"),
+                      PluginDescriptorFilesGenerator.getJavadocUrlForType( 
linkGenerator, "java.lang.Map<java.lang.String,java.lang.Integer>" ) );
+        assertEquals( 
javadocBaseUri.resolve("java/util/function/BiFunction.html"),
+                      PluginDescriptorFilesGenerator.getJavadocUrlForType( 
linkGenerator, 
"java.util.function.BiFunction<java.lang.String,java.lang.String,java.lang.String>"
 ) );
+    }
 }
\ No newline at end of file
diff --git 
a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginXdocGeneratorTest.java
 
b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginXdocGeneratorTest.java
index d4c983dc..05903058 100644
--- 
a/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginXdocGeneratorTest.java
+++ 
b/maven-plugin-tools-generators/src/test/java/org/apache/maven/tools/plugin/generator/PluginXdocGeneratorTest.java
@@ -26,6 +26,9 @@ import org.codehaus.plexus.util.ReaderFactory;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
  * @author <a href="mailto:[email protected]";>Jason van Zyl </a>
@@ -52,4 +55,12 @@ public class PluginXdocGeneratorTest
 
     }
 
+    @Test
+    void testGetShortType()
+    {
+        assertEquals("String", PluginXdocGenerator.getShortType( 
"java.lang.String" ) );
+        assertEquals("List<String>", PluginXdocGenerator.getShortType( 
"java.util.List<java.lang.String>" ) );
+        assertEquals("Map<String,Integer>", PluginXdocGenerator.getShortType( 
"java.util.Map<java.lang.String,java.lang.Integer>" ) );
+        assertEquals("List<...>", PluginXdocGenerator.getShortType( 
"java.util.List<java.util.List<java.lang.String>>" ) );
+    }
 }
diff --git a/pom.xml b/pom.xml
index 07e914a9..de7fa1e1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -246,7 +246,11 @@
         <artifactId>asm-commons</artifactId>
         <version>${asmVersion}</version>
       </dependency>
-
+      <dependency>
+        <groupId>org.ow2.asm</groupId>
+        <artifactId>asm-util</artifactId>
+        <version>${asmVersion}</version>
+      </dependency>
       <!-- testing -->
       <dependency>
         <groupId>org.apache.maven.plugin-testing</groupId>


Reply via email to