From 26679cb11a1177182231d0aa585ade2bc8c011a7 Mon Sep 17 00:00:00 2001 From: Konrad Windszus Date: Wed, 26 Oct 2022 13:25:34 +0200 Subject: [PATCH 1/3] [MPLUGIN-427] Expose generics information of parameter types in report and help mojo --- maven-plugin-tools-annotations/pom.xml | 4 + ...avaAnnotationsMojoDescriptorExtractor.java | 9 +- .../datamodel/ParameterAnnotationContent.java | 25 ++++- .../DefaultMojoAnnotationsScanner.java | 3 +- .../scanner/visitors/MojoClassVisitor.java | 47 +++++++- .../scanner/visitors/MojoFieldVisitor.java | 12 ++- .../scanner/visitors/MojoMethodVisitor.java | 12 ++- .../visitors/MojoParameterVisitor.java | 3 + .../ParametersWithGenericsMojo.java | 66 ++++++++++++ .../annotations/TestAnnotationsReader.java | 12 +-- .../DefaultMojoAnnotationsScannerTest.java | 48 +++++++++ .../PluginDescriptorFilesGenerator.java | 102 +++++++++++++----- .../plugin/generator/PluginXdocGenerator.java | 60 ++++++++++- .../PluginDescriptorFilesGeneratorTest.java | 35 ++++-- .../generator/PluginXdocGeneratorTest.java | 11 ++ pom.xml | 6 +- 16 files changed, 399 insertions(+), 56 deletions(-) create mode 100644 maven-plugin-tools-annotations/src/test/java/org/apache/maven/tools/plugin/extractor/annotations/ParametersWithGenericsMojo.java diff --git a/maven-plugin-tools-annotations/pom.xml b/maven-plugin-tools-annotations/pom.xml index 52e9f3b4d..1830d6698 100644 --- a/maven-plugin-tools-annotations/pom.xml +++ b/maven-plugin-tools-annotations/pom.xml @@ -78,6 +78,10 @@ org.ow2.asm asm + + org.ow2.asm + asm-util + org.jsoup 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 d37042932..ac7b4ea9d 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.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 @@ private List toMojoDescriptors( Map + 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 3d9f8922e..6ac23be50 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.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 typeParameters; + + public ParameterAnnotationContent( String fieldName, String className, List 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 typeParameters ) { - this( fieldName, className ); + this( fieldName, className, typeParameters ); this.alias = alias; this.property = property; this.defaultValue = defaultValue; @@ -177,6 +182,11 @@ public void setClassName( String className ) this.className = className; } + public List getTypeParameters() + { + return typeParameters; + } + @Override public String toString() { @@ -185,6 +195,7 @@ public String toString() 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 boolean equals( Object o ) return false; } + if ( !Objects.equals( typeParameters, that.typeParameters ) ) + { + return false; + } if ( !Objects.equals( alias, that.alias ) ) { return false; @@ -253,7 +268,7 @@ public boolean equals( Object o ) @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 2b441751c..c0e3ed886 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 @@ protected void analyzeVisitors( MojoClassVisitor mojoClassVisitor ) for ( MojoParameterVisitor parameterVisitor : mojoParameterVisitors ) { ParameterAnnotationContent parameterAnnotationContent = - new ParameterAnnotationContent( parameterVisitor.getFieldName(), parameterVisitor.getClassName() ); + new ParameterAnnotationContent( parameterVisitor.getFieldName(), parameterVisitor.getClassName(), + parameterVisitor.getTypeParameters() ); Map 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 9376564d5..6267d64ff 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 @@ */ 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.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 AnnotationVisitor visitAnnotation( String desc, boolean visible ) @Override public FieldVisitor visitField( int access, String name, String desc, String signature, Object value ) { - MojoFieldVisitor mojoFieldVisitor = new MojoFieldVisitor( name, Type.getType( desc ).getClassName() ); + List 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 + * JVMS 4.3.4 + * and returns the type parameters. + * @param access + * @param signature + * @param isField + * @return the list of type parameters (may be empty) + */ + private List 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 MethodVisitor visitMethod( int access, String name, String desc, String s { String fieldName = StringUtils.lowercaseFirstLetter( name.substring( 3 ) ); String className = type.getArgumentTypes()[0].getClassName(); + List 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 550bd579d..3e017afc3 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 @@ */ 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 typeParameters; + + MojoFieldVisitor( String fieldName, String className, List typeParameters ) { super( Opcodes.ASM9 ); this.fieldName = fieldName; this.className = className; + this.typeParameters = typeParameters; } @Override @@ -62,6 +66,12 @@ public String getFieldName() return fieldName; } + @Override + public List 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 448bb7880..dd121f728 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 @@ */ 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 typeParameters; private Map annotationVisitorMap = new HashMap<>(); - public MojoMethodVisitor( String fieldName, String className ) + public MojoMethodVisitor( String fieldName, String className, List typeParameters ) { super( Opcodes.ASM9 ); this.fieldName = fieldName; this.className = className; + this.typeParameters = typeParameters; } @Override @@ -73,6 +75,12 @@ public String getClassName() return className; } + @Override + public List getTypeParameters() + { + return typeParameters; + } + @Override public Map 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 c95ac05c2..e9ba40570 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 @@ * under the License. */ +import java.util.List; import java.util.Map; /** @@ -32,5 +33,7 @@ public interface MojoParameterVisitor String getClassName(); + List getTypeParameters(); + Map 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 000000000..5a1d3a269 --- /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 stringBooleanMap; + + @Parameter + private Collection integerCollection; + + @Parameter + private Collection> nestedStringCollection; + + @Parameter + private Collection integerArrayCollection; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + } + + @Parameter( name="numberList" ) + public void setNumberList(List numberList) { + } + + public static class NestedClass { + /** + * 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 81796881c..dca5896c2 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 @@ void testReadMojoClass() .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 87dfc4e50..cc99b0691 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 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 @@ void scanDeprecatedMojoAnnotatins() throws ExtractionException, IOException .isEqualTo( "property.anotherNotDeprecated" ); } + @Test + void scanParametersWithGenerics() throws ExtractionException, IOException + { + File directoryToScan = new File( ParametersWithGenericsMojo.class.getResource( "" ).getFile() ); + + scanner.enableLogging( mock( Logger.class ) ); + Map 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() ).contains( "java.lang.String", "java.lang.Boolean" ); + + parameter = annotatedClass.getParameters().get( "integerCollection" ); + assertNotNull( parameter ); + assertEquals( "java.util.Collection", parameter.getClassName() ); + assertThat( parameter.getTypeParameters() ).contains( "java.lang.Integer" ); + + parameter = annotatedClass.getParameters().get( "nestedStringCollection" ); + assertNotNull( parameter ); + assertEquals( "java.util.Collection", parameter.getClassName() ); + assertThat( parameter.getTypeParameters() ).contains( "java.util.Collection" ); + + parameter = annotatedClass.getParameters().get( "integerArrayCollection" ); + assertNotNull( parameter ); + assertEquals( "java.util.Collection", parameter.getClassName() ); + assertThat( parameter.getTypeParameters() ).contains( "java.lang.Integer[]" ); + + parameter = annotatedClass.getParameters().get( "numberList" ); + assertNotNull( parameter ); + assertEquals( "java.util.List", parameter.getClassName() ); + assertThat( parameter.getTypeParameters() ).contains( "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 1f0f00c8a..62517c702 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 @@ else if ( type != DescriptorType.LIMITED_FOR_HELP_MOJO || parameter.isEditable() 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 @@ else if ( type != DescriptorType.LIMITED_FOR_HELP_MOJO || parameter.isEditable() 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 ${ }. * 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 9344cae85..c13a17908 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 @@ private void writeParameterDetails( List parameterList, XMLWriter w ) 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 @@ private String getLinkedType( Parameter parameter, boolean isShortType ) 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 0187af033..cf8a7dc86 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 @@ -1,5 +1,15 @@ package org.apache.maven.tools.plugin.generator; +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; + /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -23,17 +33,11 @@ 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 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.util.List; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -131,4 +135,19 @@ private void checkDependency( String groupId, String artifactId, String version, 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" ) ); + assertEquals( javadocBaseUri.resolve("java/lang/Integer.html"), + PluginDescriptorFilesGenerator.getJavadocUrlForType( linkGenerator, "java.lang.Map" ) ); + assertEquals( javadocBaseUri.resolve("java/util/function/BiFunction.html"), + PluginDescriptorFilesGenerator.getJavadocUrlForType( linkGenerator, "java.util.function.BiFunction" ) ); + } } \ 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 d4c983dc2..05903058b 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.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 Jason van Zyl @@ -52,4 +55,12 @@ protected void validate( File destinationDirectory ) } + @Test + void testGetShortType() + { + assertEquals("String", PluginXdocGenerator.getShortType( "java.lang.String" ) ); + assertEquals("List", PluginXdocGenerator.getShortType( "java.util.List" ) ); + assertEquals("Map", PluginXdocGenerator.getShortType( "java.util.Map" ) ); + assertEquals("List<...>", PluginXdocGenerator.getShortType( "java.util.List>" ) ); + } } diff --git a/pom.xml b/pom.xml index 07e914a9d..de7fa1e13 100644 --- a/pom.xml +++ b/pom.xml @@ -246,7 +246,11 @@ asm-commons ${asmVersion} - + + org.ow2.asm + asm-util + ${asmVersion} + org.apache.maven.plugin-testing From 4816ac73c9f622a7122c56ee6b478c39b6bc7211 Mon Sep 17 00:00:00 2001 From: Konrad Windszus Date: Wed, 26 Oct 2022 14:34:28 +0200 Subject: [PATCH 2/3] improve tests --- .../scanner/DefaultMojoAnnotationsScannerTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 cc99b0691..9c8f0b8d7 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 @@ -102,26 +102,26 @@ void scanParametersWithGenerics() throws ExtractionException, IOException parameter = annotatedClass.getParameters().get( "stringBooleanMap" ); assertNotNull( parameter ); assertEquals( "java.util.Map", parameter.getClassName() ); - assertThat( parameter.getTypeParameters() ).contains( "java.lang.String", "java.lang.Boolean" ); + 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() ).contains( "java.lang.Integer" ); + assertThat( parameter.getTypeParameters() ).containsExactly( "java.lang.Integer" ); parameter = annotatedClass.getParameters().get( "nestedStringCollection" ); assertNotNull( parameter ); assertEquals( "java.util.Collection", parameter.getClassName() ); - assertThat( parameter.getTypeParameters() ).contains( "java.util.Collection" ); + assertThat( parameter.getTypeParameters() ).containsExactly( "java.util.Collection" ); parameter = annotatedClass.getParameters().get( "integerArrayCollection" ); assertNotNull( parameter ); assertEquals( "java.util.Collection", parameter.getClassName() ); - assertThat( parameter.getTypeParameters() ).contains( "java.lang.Integer[]" ); + assertThat( parameter.getTypeParameters() ).containsExactly( "java.lang.Integer[]" ); parameter = annotatedClass.getParameters().get( "numberList" ); assertNotNull( parameter ); assertEquals( "java.util.List", parameter.getClassName() ); - assertThat( parameter.getTypeParameters() ).contains( "java.lang.Number" ); + assertThat( parameter.getTypeParameters() ).containsExactly( "java.lang.Number" ); } } From ecf301043368578dd749a7cca8c781cc0648c1a4 Mon Sep 17 00:00:00 2001 From: Konrad Windszus Date: Wed, 26 Oct 2022 15:58:28 +0200 Subject: [PATCH 3/3] cleanup --- .../PluginDescriptorFilesGenerator.java | 2 +- .../PluginDescriptorFilesGeneratorTest.java | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) 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 62517c702..a21a4e443 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 @@ -687,7 +687,7 @@ protected void writeParameterType( XMLWriter w, DescriptorType type, JavadocLink } } - static URI getJavadocUrlForType( JavadocLinkGenerator javadocLinkGenerator, String type ) + static URI getJavadocUrlForType( JavadocLinkGenerator javadocLinkGenerator, String type ) { final String binaryName; int startOfParameterType = type.indexOf( "<" ); 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 cf8a7dc86..3e8decd8e 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 @@ -1,15 +1,5 @@ package org.apache.maven.tools.plugin.generator; -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; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -29,6 +19,16 @@ * under the License. */ +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;