Skip to content

Commit a0ec0ba

Browse files
authored
[MPLUGIN-427] Expose generics information of parameter types in report (#159)
1 parent 14e3d38 commit a0ec0ba

File tree

16 files changed

+399
-56
lines changed

16 files changed

+399
-56
lines changed

maven-plugin-tools-annotations/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@
7878
<groupId>org.ow2.asm</groupId>
7979
<artifactId>asm</artifactId>
8080
</dependency>
81+
<dependency>
82+
<groupId>org.ow2.asm</groupId>
83+
<artifactId>asm-util</artifactId>
84+
</dependency>
8185
<!-- for HTML to plain text conversion -->
8286
<dependency>
8387
<groupId>org.jsoup</groupId>

maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/JavaAnnotationsMojoDescriptorExtractor.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.util.Set;
4040
import java.util.TreeMap;
4141
import java.util.TreeSet;
42+
import java.util.stream.Collectors;
4243

4344
import com.thoughtworks.qdox.JavaProjectBuilder;
4445
import com.thoughtworks.qdox.library.SortedClassLibraryBuilder;
@@ -698,7 +699,13 @@ private List<MojoDescriptor> toMojoDescriptors( Map<String, MojoAnnotatedClass>
698699
+ property, null );
699700
}
700701
parameter.setExpression( StringUtils.isEmpty( property ) ? "" : "${" + property + "}" );
701-
parameter.setType( parameterAnnotationContent.getClassName() );
702+
StringBuilder type = new StringBuilder( parameterAnnotationContent.getClassName() );
703+
if ( !parameterAnnotationContent.getTypeParameters().isEmpty() )
704+
{
705+
type.append( parameterAnnotationContent.getTypeParameters().stream()
706+
.collect( Collectors.joining( ", ", "<", ">" ) ) );
707+
}
708+
parameter.setType( type.toString() );
702709
parameter.setSince( parameterAnnotationContent.getSince() );
703710
parameter.setRequired( parameterAnnotationContent.required() );
704711

maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/datamodel/ParameterAnnotationContent.java

+20-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.objectweb.asm.Type;
2424

2525
import java.lang.annotation.Annotation;
26+
import java.util.List;
2627
import java.util.Objects;
2728

2829
/**
@@ -50,16 +51,20 @@ public class ParameterAnnotationContent
5051

5152
private String className;
5253

53-
public ParameterAnnotationContent( String fieldName, String className )
54+
private final List<String> typeParameters;
55+
56+
public ParameterAnnotationContent( String fieldName, String className, List<String> typeParameters )
5457
{
5558
super( fieldName );
5659
this.className = className;
60+
this.typeParameters = typeParameters;
5761
}
5862

5963
public ParameterAnnotationContent( String fieldName, String alias, String property, String defaultValue,
60-
Class<?> implementation, boolean required, boolean readonly, String className )
64+
Class<?> implementation, boolean required, boolean readonly, String className,
65+
List<String> typeParameters )
6166
{
62-
this( fieldName, className );
67+
this( fieldName, className, typeParameters );
6368
this.alias = alias;
6469
this.property = property;
6570
this.defaultValue = defaultValue;
@@ -177,6 +182,11 @@ public void setClassName( String className )
177182
this.className = className;
178183
}
179184

185+
public List<String> getTypeParameters()
186+
{
187+
return typeParameters;
188+
}
189+
180190
@Override
181191
public String toString()
182192
{
@@ -185,6 +195,7 @@ public String toString()
185195
sb.append( "ParameterAnnotationContent" );
186196
sb.append( "{fieldName='" ).append( getFieldName() ).append( '\'' );
187197
sb.append( ", className='" ).append( getClassName() ).append( '\'' );
198+
sb.append( ", typeParameters='" ).append( getTypeParameters() ).append( '\'' );
188199
sb.append( ", name='" ).append( name ).append( '\'' );
189200
sb.append( ", alias='" ).append( alias ).append( '\'' );
190201
sb.append( ", alias='" ).append( alias ).append( '\'' );
@@ -230,6 +241,10 @@ public boolean equals( Object o )
230241
return false;
231242
}
232243

244+
if ( !Objects.equals( typeParameters, that.typeParameters ) )
245+
{
246+
return false;
247+
}
233248
if ( !Objects.equals( alias, that.alias ) )
234249
{
235250
return false;
@@ -253,7 +268,7 @@ public boolean equals( Object o )
253268
@Override
254269
public int hashCode()
255270
{
256-
return Objects.hash( alias, getFieldName(), property, defaultValue, required, readonly,
257-
implementationClassName );
271+
return Objects.hash( alias, getFieldName(), getClassName(), typeParameters, property, defaultValue, required,
272+
readonly, implementationClassName );
258273
}
259274
}

maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/DefaultMojoAnnotationsScanner.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,8 @@ protected void analyzeVisitors( MojoClassVisitor mojoClassVisitor )
302302
for ( MojoParameterVisitor parameterVisitor : mojoParameterVisitors )
303303
{
304304
ParameterAnnotationContent parameterAnnotationContent =
305-
new ParameterAnnotationContent( parameterVisitor.getFieldName(), parameterVisitor.getClassName() );
305+
new ParameterAnnotationContent( parameterVisitor.getFieldName(), parameterVisitor.getClassName(),
306+
parameterVisitor.getTypeParameters() );
306307

307308
Map<String, MojoAnnotationVisitor> annotationVisitorMap = parameterVisitor.getAnnotationVisitorMap();
308309
MojoAnnotationVisitor fieldAnnotationVisitor = annotationVisitorMap.get( Parameter.class.getName() );

maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoClassVisitor.java

+45-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
*/
2121

2222
import java.util.ArrayList;
23+
import java.util.Arrays;
24+
import java.util.Collections;
2325
import java.util.HashMap;
2426
import java.util.List;
2527
import java.util.Map;
@@ -36,6 +38,8 @@
3638
import org.objectweb.asm.MethodVisitor;
3739
import org.objectweb.asm.Opcodes;
3840
import org.objectweb.asm.Type;
41+
import org.objectweb.asm.signature.SignatureReader;
42+
import org.objectweb.asm.util.TraceSignatureVisitor;
3943

4044
/**
4145
* Visitor for Mojo classes.
@@ -117,11 +121,49 @@ public AnnotationVisitor visitAnnotation( String desc, boolean visible )
117121
@Override
118122
public FieldVisitor visitField( int access, String name, String desc, String signature, Object value )
119123
{
120-
MojoFieldVisitor mojoFieldVisitor = new MojoFieldVisitor( name, Type.getType( desc ).getClassName() );
124+
List<String> typeParameters = extractTypeParameters( access, signature, true );
125+
MojoFieldVisitor mojoFieldVisitor = new MojoFieldVisitor( name, Type.getType( desc ).getClassName(),
126+
typeParameters );
121127
fieldVisitors.add( mojoFieldVisitor );
122128
return mojoFieldVisitor;
123129
}
124130

131+
/**
132+
* Parses the signature according to
133+
* <a href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.4">JVMS 4.3.4</a>
134+
* and returns the type parameters.
135+
* @param access
136+
* @param signature
137+
* @param isField
138+
* @return the list of type parameters (may be empty)
139+
*/
140+
private List<String> extractTypeParameters( int access, String signature, boolean isField )
141+
{
142+
if ( StringUtils.isEmpty( signature ) )
143+
{
144+
return Collections.emptyList();
145+
}
146+
TraceSignatureVisitor traceSignatureVisitor = new TraceSignatureVisitor( access );
147+
SignatureReader signatureReader = new SignatureReader( signature );
148+
if ( isField )
149+
{
150+
signatureReader.acceptType( traceSignatureVisitor );
151+
}
152+
else
153+
{
154+
signatureReader.accept( traceSignatureVisitor );
155+
}
156+
String declaration = traceSignatureVisitor.getDeclaration();
157+
int startTypeParameters = declaration.indexOf( '<' );
158+
if ( startTypeParameters == -1 )
159+
{
160+
return Collections.emptyList();
161+
}
162+
String typeParameters = declaration.substring( startTypeParameters + 1,
163+
declaration.lastIndexOf( '>' ) );
164+
return Arrays.asList( typeParameters.split( ", " ) );
165+
}
166+
125167
@Override
126168
public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions )
127169
{
@@ -142,8 +184,9 @@ public MethodVisitor visitMethod( int access, String name, String desc, String s
142184
{
143185
String fieldName = StringUtils.lowercaseFirstLetter( name.substring( 3 ) );
144186
String className = type.getArgumentTypes()[0].getClassName();
187+
List<String> typeParameters = extractTypeParameters( access, signature, false );
145188

146-
MojoMethodVisitor mojoMethodVisitor = new MojoMethodVisitor( fieldName, className );
189+
MojoMethodVisitor mojoMethodVisitor = new MojoMethodVisitor( fieldName, className, typeParameters );
147190
methodVisitors.add( mojoMethodVisitor );
148191
return mojoMethodVisitor;
149192
}

maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoFieldVisitor.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121

2222
import java.util.HashMap;
23+
import java.util.List;
2324
import java.util.Map;
2425

2526
import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotationsScanner;
@@ -43,11 +44,14 @@ public class MojoFieldVisitor
4344

4445
private String className;
4546

46-
MojoFieldVisitor( String fieldName, String className )
47+
private final List<String> typeParameters;
48+
49+
MojoFieldVisitor( String fieldName, String className, List<String> typeParameters )
4750
{
4851
super( Opcodes.ASM9 );
4952
this.fieldName = fieldName;
5053
this.className = className;
54+
this.typeParameters = typeParameters;
5155
}
5256

5357
@Override
@@ -62,6 +66,12 @@ public String getFieldName()
6266
return fieldName;
6367
}
6468

69+
@Override
70+
public List<String> getTypeParameters()
71+
{
72+
return typeParameters;
73+
}
74+
6575
@Override
6676
public AnnotationVisitor visitAnnotation( String desc, boolean visible )
6777
{

maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoMethodVisitor.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121

2222
import java.util.HashMap;
23+
import java.util.List;
2324
import java.util.Map;
2425

2526
import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotationsScanner;
@@ -37,14 +38,15 @@ public class MojoMethodVisitor extends MethodVisitor implements MojoParameterVis
3738
{
3839
private final String className;
3940
private final String fieldName;
40-
41+
private final List<String> typeParameters;
4142
private Map<String, MojoAnnotationVisitor> annotationVisitorMap = new HashMap<>();
4243

43-
public MojoMethodVisitor( String fieldName, String className )
44+
public MojoMethodVisitor( String fieldName, String className, List<String> typeParameters )
4445
{
4546
super( Opcodes.ASM9 );
4647
this.fieldName = fieldName;
4748
this.className = className;
49+
this.typeParameters = typeParameters;
4850
}
4951

5052
@Override
@@ -73,6 +75,12 @@ public String getClassName()
7375
return className;
7476
}
7577

78+
@Override
79+
public List<String> getTypeParameters()
80+
{
81+
return typeParameters;
82+
}
83+
7684
@Override
7785
public Map<String, MojoAnnotationVisitor> getAnnotationVisitorMap()
7886
{

maven-plugin-tools-annotations/src/main/java/org/apache/maven/tools/plugin/extractor/annotations/scanner/visitors/MojoParameterVisitor.java

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* under the License.
2020
*/
2121

22+
import java.util.List;
2223
import java.util.Map;
2324

2425
/**
@@ -32,5 +33,7 @@ public interface MojoParameterVisitor
3233

3334
String getClassName();
3435

36+
List<String> getTypeParameters();
37+
3538
Map<String, MojoAnnotationVisitor> getAnnotationVisitorMap();
3639
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.apache.maven.tools.plugin.extractor.annotations;
2+
3+
/*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
import java.util.Collection;
23+
import java.util.List;
24+
import java.util.Map;
25+
26+
import org.apache.maven.plugin.AbstractMojo;
27+
import org.apache.maven.plugin.MojoExecutionException;
28+
import org.apache.maven.plugin.MojoFailureException;
29+
import org.apache.maven.plugins.annotations.Mojo;
30+
import org.apache.maven.plugins.annotations.Parameter;
31+
32+
@Mojo( name = "parameter-with-generics" )
33+
public class ParametersWithGenericsMojo
34+
extends AbstractMojo
35+
{
36+
37+
@Parameter
38+
private String string;
39+
40+
@Parameter
41+
private Map<String, Boolean> stringBooleanMap;
42+
43+
@Parameter
44+
private Collection<Integer> integerCollection;
45+
46+
@Parameter
47+
private Collection<Collection<String>> nestedStringCollection;
48+
49+
@Parameter
50+
private Collection<Integer[]> integerArrayCollection;
51+
52+
@Override
53+
public void execute() throws MojoExecutionException, MojoFailureException {
54+
}
55+
56+
@Parameter( name="numberList" )
57+
public void setNumberList(List<Number> numberList) {
58+
}
59+
60+
public static class NestedClass<E extends Number> {
61+
/**
62+
* Some field without type parameter but non-empty signature
63+
*/
64+
protected E filter;
65+
}
66+
}

maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/TestAnnotationsReader.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -98,25 +98,25 @@ void testReadMojoClass()
9898
.hasSize( 6 )
9999
.containsExactlyInAnyOrder(
100100
new ParameterAnnotationContent( "bar", null, "thebar", "coolbar", null, true, false,
101-
String.class.getName() ),
101+
String.class.getName(), Collections.emptyList() ),
102102
new ParameterAnnotationContent( "beer", null, "thebeer", "coolbeer", null, false, false,
103-
String.class.getName() ),
103+
String.class.getName(), Collections.emptyList() ),
104104
new ParameterAnnotationContent( "fooInterface", null, "fooInterface", null,
105105
FooInterfaceImpl.class,
106106
false,
107-
false, FooInterface.class.getName() ),
107+
false, FooInterface.class.getName(), Collections.emptyList() ),
108108
new ParameterAnnotationContent( "paramFromSetter", null, "props.paramFromSetter", null,
109109
null,
110110
false,
111-
false, String.class.getName() ),
111+
false, String.class.getName(), Collections.emptyList() ),
112112
new ParameterAnnotationContent( "paramFromAdd", null, "props.paramFromAdd", null,
113113
null,
114114
false,
115-
false, String.class.getName() ),
115+
false, String.class.getName(), Collections.emptyList() ),
116116
new ParameterAnnotationContent( "paramFromSetterDeprecated", null, "props.paramFromSetterDeprecated", null,
117117
null,
118118
false,
119-
false, List.class.getName() )
119+
false, List.class.getName(), Collections.singletonList("java.lang.String") )
120120
);
121121
}
122122
}

0 commit comments

Comments
 (0)