001package org.apache.maven.tools.plugin.extractor.annotations; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.net.MalformedURLException; 024import java.net.URL; 025import java.net.URLClassLoader; 026import java.util.ArrayList; 027import java.util.Arrays; 028import java.util.Collection; 029import java.util.Collections; 030import java.util.HashMap; 031import java.util.HashSet; 032import java.util.List; 033import java.util.Map; 034import java.util.Objects; 035import java.util.Set; 036import java.util.TreeMap; 037import java.util.TreeSet; 038 039import org.apache.maven.artifact.Artifact; 040import org.apache.maven.artifact.factory.ArtifactFactory; 041import org.apache.maven.artifact.resolver.ArtifactNotFoundException; 042import org.apache.maven.artifact.resolver.ArtifactResolutionException; 043import org.apache.maven.artifact.resolver.ArtifactResolver; 044import org.apache.maven.plugin.descriptor.DuplicateParameterException; 045import org.apache.maven.plugin.descriptor.InvalidParameterException; 046import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException; 047import org.apache.maven.plugin.descriptor.MojoDescriptor; 048import org.apache.maven.plugin.descriptor.PluginDescriptor; 049import org.apache.maven.plugin.descriptor.Requirement; 050import org.apache.maven.project.MavenProject; 051import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; 052import org.apache.maven.tools.plugin.PluginToolsRequest; 053import org.apache.maven.tools.plugin.extractor.ExtractionException; 054import org.apache.maven.tools.plugin.extractor.MojoDescriptorExtractor; 055import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ComponentAnnotationContent; 056import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ExecuteAnnotationContent; 057import org.apache.maven.tools.plugin.extractor.annotations.datamodel.MojoAnnotationContent; 058import org.apache.maven.tools.plugin.extractor.annotations.datamodel.ParameterAnnotationContent; 059import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotatedClass; 060import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotationsScanner; 061import org.apache.maven.tools.plugin.extractor.annotations.scanner.MojoAnnotationsScannerRequest; 062import org.apache.maven.tools.plugin.util.PluginUtils; 063import org.codehaus.plexus.archiver.UnArchiver; 064import org.codehaus.plexus.archiver.manager.ArchiverManager; 065import org.codehaus.plexus.archiver.manager.NoSuchArchiverException; 066import org.codehaus.plexus.component.annotations.Component; 067import org.codehaus.plexus.logging.AbstractLogEnabled; 068import org.codehaus.plexus.util.StringUtils; 069 070import com.thoughtworks.qdox.JavaProjectBuilder; 071import com.thoughtworks.qdox.library.SortedClassLibraryBuilder; 072import com.thoughtworks.qdox.model.DocletTag; 073import com.thoughtworks.qdox.model.JavaClass; 074import com.thoughtworks.qdox.model.JavaField; 075 076/** 077 * JavaMojoDescriptorExtractor, a MojoDescriptor extractor to read descriptors from java classes with annotations. 078 * Notice that source files are also parsed to get description, since and deprecation information. 079 * 080 * @author Olivier Lamy 081 * @since 3.0 082 */ 083@Component( role = MojoDescriptorExtractor.class, hint = "java-annotations" ) 084public class JavaAnnotationsMojoDescriptorExtractor 085 extends AbstractLogEnabled 086 implements MojoDescriptorExtractor 087{ 088 089 @org.codehaus.plexus.component.annotations.Requirement 090 private MojoAnnotationsScanner mojoAnnotationsScanner; 091 092 @org.codehaus.plexus.component.annotations.Requirement 093 private ArtifactResolver artifactResolver; 094 095 @org.codehaus.plexus.component.annotations.Requirement 096 private ArtifactFactory artifactFactory; 097 098 @org.codehaus.plexus.component.annotations.Requirement 099 private ArchiverManager archiverManager; 100 101 @Override 102 public List<MojoDescriptor> execute( PluginToolsRequest request ) 103 throws ExtractionException, InvalidPluginDescriptorException 104 { 105 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses = scanAnnotations( request ); 106 107 Map<String, JavaClass> javaClassesMap = scanJavadoc( request, mojoAnnotatedClasses.values() ); 108 109 populateDataFromJavadoc( mojoAnnotatedClasses, javaClassesMap ); 110 111 return toMojoDescriptors( mojoAnnotatedClasses, request.getPluginDescriptor() ); 112 } 113 114 private Map<String, MojoAnnotatedClass> scanAnnotations( PluginToolsRequest request ) 115 throws ExtractionException 116 { 117 MojoAnnotationsScannerRequest mojoAnnotationsScannerRequest = new MojoAnnotationsScannerRequest(); 118 119 File output = new File( request.getProject().getBuild().getOutputDirectory() ); 120 mojoAnnotationsScannerRequest.setClassesDirectories( Arrays.asList( output ) ); 121 122 mojoAnnotationsScannerRequest.setDependencies( request.getDependencies() ); 123 124 mojoAnnotationsScannerRequest.setProject( request.getProject() ); 125 126 return mojoAnnotationsScanner.scan( mojoAnnotationsScannerRequest ); 127 } 128 129 private Map<String, JavaClass> scanJavadoc( PluginToolsRequest request, 130 Collection<MojoAnnotatedClass> mojoAnnotatedClasses ) 131 throws ExtractionException 132 { 133 // found artifact from reactors to scan sources 134 // we currently only scan sources from reactors 135 List<MavenProject> mavenProjects = new ArrayList<>(); 136 137 // if we need to scan sources from external artifacts 138 Set<Artifact> externalArtifacts = new HashSet<>(); 139 140 for ( MojoAnnotatedClass mojoAnnotatedClass : mojoAnnotatedClasses ) 141 { 142 if ( Objects.equals( mojoAnnotatedClass.getArtifact().getArtifactId(), 143 request.getProject().getArtifact().getArtifactId() ) ) 144 { 145 continue; 146 } 147 148 if ( !isMojoAnnnotatedClassCandidate( mojoAnnotatedClass ) ) 149 { 150 // we don't scan sources for classes without mojo annotations 151 continue; 152 } 153 154 MavenProject mavenProject = 155 getFromProjectReferences( mojoAnnotatedClass.getArtifact(), request.getProject() ); 156 157 if ( mavenProject != null ) 158 { 159 mavenProjects.add( mavenProject ); 160 } 161 else 162 { 163 externalArtifacts.add( mojoAnnotatedClass.getArtifact() ); 164 } 165 } 166 167 Map<String, JavaClass> javaClassesMap = new HashMap<String, JavaClass>(); 168 169 // try to get artifact with sources classifier, extract somewhere then scan for @since, @deprecated 170 for ( Artifact artifact : externalArtifacts ) 171 { 172 // parameter for test-sources too ?? olamy I need that for it test only 173 if ( StringUtils.equalsIgnoreCase( "tests", artifact.getClassifier() ) ) 174 { 175 javaClassesMap.putAll( discoverClassesFromSourcesJar( artifact, request, "test-sources" ) ); 176 } 177 else 178 { 179 javaClassesMap.putAll( discoverClassesFromSourcesJar( artifact, request, "sources" ) ); 180 } 181 182 } 183 184 for ( MavenProject mavenProject : mavenProjects ) 185 { 186 javaClassesMap.putAll( discoverClasses( request.getEncoding(), mavenProject ) ); 187 } 188 189 javaClassesMap.putAll( discoverClasses( request ) ); 190 191 return javaClassesMap; 192 } 193 194 private boolean isMojoAnnnotatedClassCandidate( MojoAnnotatedClass mojoAnnotatedClass ) 195 { 196 return mojoAnnotatedClass != null && mojoAnnotatedClass.hasAnnotations(); 197 } 198 199 protected Map<String, JavaClass> discoverClassesFromSourcesJar( Artifact artifact, PluginToolsRequest request, 200 String classifier ) 201 throws ExtractionException 202 { 203 try 204 { 205 Artifact sourcesArtifact = 206 artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(), 207 artifact.getVersion(), artifact.getType(), classifier ); 208 209 artifactResolver.resolve( sourcesArtifact, request.getRemoteRepos(), request.getLocal() ); 210 211 if ( sourcesArtifact.getFile() == null || !sourcesArtifact.getFile().exists() ) 212 { 213 // could not get artifact sources 214 return Collections.emptyMap(); 215 } 216 217 // extract sources to target/maven-plugin-plugin-sources/${groupId}/${artifact}/sources 218 File extractDirectory = new File( request.getProject().getBuild().getDirectory(), 219 "maven-plugin-plugin-sources/" + sourcesArtifact.getGroupId() + "/" 220 + sourcesArtifact.getArtifactId() + "/" + sourcesArtifact.getVersion() 221 + "/" + sourcesArtifact.getClassifier() ); 222 extractDirectory.mkdirs(); 223 224 UnArchiver unArchiver = archiverManager.getUnArchiver( "jar" ); 225 unArchiver.setSourceFile( sourcesArtifact.getFile() ); 226 unArchiver.setDestDirectory( extractDirectory ); 227 unArchiver.extract(); 228 229 return discoverClasses( request.getEncoding(), Arrays.asList( extractDirectory ), 230 request.getDependencies() ); 231 } 232 catch ( ArtifactResolutionException e ) 233 { 234 throw new ExtractionException( e.getMessage(), e ); 235 } 236 catch ( ArtifactNotFoundException e ) 237 { 238 //throw new ExtractionException( e.getMessage(), e ); 239 getLogger().debug( "skip ArtifactNotFoundException:" + e.getMessage() ); 240 getLogger().warn( 241 "Unable to get sources artifact for " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" 242 + artifact.getVersion() + ". Some javadoc tags (@since, @deprecated and comments) won't be used" ); 243 return Collections.emptyMap(); 244 } 245 catch ( NoSuchArchiverException e ) 246 { 247 throw new ExtractionException( e.getMessage(), e ); 248 } 249 } 250 251 /** 252 * from sources scan to get @since and @deprecated and description of classes and fields. 253 * 254 * @param mojoAnnotatedClasses 255 * @param javaClassesMap 256 */ 257 protected void populateDataFromJavadoc( Map<String, MojoAnnotatedClass> mojoAnnotatedClasses, 258 Map<String, JavaClass> javaClassesMap ) 259 { 260 261 for ( Map.Entry<String, MojoAnnotatedClass> entry : mojoAnnotatedClasses.entrySet() ) 262 { 263 JavaClass javaClass = javaClassesMap.get( entry.getKey() ); 264 if ( javaClass == null ) 265 { 266 continue; 267 } 268 269 // populate class-level content 270 MojoAnnotationContent mojoAnnotationContent = entry.getValue().getMojo(); 271 if ( mojoAnnotationContent != null ) 272 { 273 mojoAnnotationContent.setDescription( javaClass.getComment() ); 274 275 DocletTag since = findInClassHierarchy( javaClass, "since" ); 276 if ( since != null ) 277 { 278 mojoAnnotationContent.setSince( since.getValue() ); 279 } 280 281 DocletTag deprecated = findInClassHierarchy( javaClass, "deprecated" ); 282 if ( deprecated != null ) 283 { 284 mojoAnnotationContent.setDeprecated( deprecated.getValue() ); 285 } 286 } 287 288 Map<String, JavaField> fieldsMap = extractFieldParameterTags( javaClass, javaClassesMap ); 289 290 // populate parameters 291 Map<String, ParameterAnnotationContent> parameters = 292 getParametersParentHierarchy( entry.getValue(), new HashMap<String, ParameterAnnotationContent>(), 293 mojoAnnotatedClasses ); 294 parameters = new TreeMap<>( parameters ); 295 for ( Map.Entry<String, ParameterAnnotationContent> parameter : parameters.entrySet() ) 296 { 297 JavaField javaField = fieldsMap.get( parameter.getKey() ); 298 if ( javaField == null ) 299 { 300 continue; 301 } 302 303 ParameterAnnotationContent parameterAnnotationContent = parameter.getValue(); 304 parameterAnnotationContent.setDescription( javaField.getComment() ); 305 306 DocletTag deprecated = javaField.getTagByName( "deprecated" ); 307 if ( deprecated != null ) 308 { 309 parameterAnnotationContent.setDeprecated( deprecated.getValue() ); 310 } 311 312 DocletTag since = javaField.getTagByName( "since" ); 313 if ( since != null ) 314 { 315 parameterAnnotationContent.setSince( since.getValue() ); 316 } 317 } 318 319 // populate components 320 Map<String, ComponentAnnotationContent> components = entry.getValue().getComponents(); 321 for ( Map.Entry<String, ComponentAnnotationContent> component : components.entrySet() ) 322 { 323 JavaField javaField = fieldsMap.get( component.getKey() ); 324 if ( javaField == null ) 325 { 326 continue; 327 } 328 329 ComponentAnnotationContent componentAnnotationContent = component.getValue(); 330 componentAnnotationContent.setDescription( javaField.getComment() ); 331 332 DocletTag deprecated = javaField.getTagByName( "deprecated" ); 333 if ( deprecated != null ) 334 { 335 componentAnnotationContent.setDeprecated( deprecated.getValue() ); 336 } 337 338 DocletTag since = javaField.getTagByName( "since" ); 339 if ( since != null ) 340 { 341 componentAnnotationContent.setSince( since.getValue() ); 342 } 343 } 344 345 } 346 347 } 348 349 /** 350 * @param javaClass not null 351 * @param tagName not null 352 * @return docletTag instance 353 */ 354 private DocletTag findInClassHierarchy( JavaClass javaClass, String tagName ) 355 { 356 DocletTag tag = javaClass.getTagByName( tagName ); 357 358 if ( tag == null ) 359 { 360 JavaClass superClass = javaClass.getSuperJavaClass(); 361 362 if ( superClass != null ) 363 { 364 tag = findInClassHierarchy( superClass, tagName ); 365 } 366 } 367 368 return tag; 369 } 370 371 /** 372 * extract fields that are either parameters or components. 373 * 374 * @param javaClass not null 375 * @return map with Mojo parameters names as keys 376 */ 377 private Map<String, JavaField> extractFieldParameterTags( JavaClass javaClass, 378 Map<String, JavaClass> javaClassesMap ) 379 { 380 Map<String, JavaField> rawParams = new TreeMap<String, com.thoughtworks.qdox.model.JavaField>(); 381 382 // we have to add the parent fields first, so that they will be overwritten by the local fields if 383 // that actually happens... 384 JavaClass superClass = javaClass.getSuperJavaClass(); 385 386 if ( superClass != null ) 387 { 388 if ( superClass.getFields().size() > 0 ) 389 { 390 rawParams = extractFieldParameterTags( superClass, javaClassesMap ); 391 } 392 // maybe sources comes from scan of sources artifact 393 superClass = javaClassesMap.get( superClass.getFullyQualifiedName() ); 394 if ( superClass != null ) 395 { 396 rawParams = extractFieldParameterTags( superClass, javaClassesMap ); 397 } 398 } 399 else 400 { 401 402 rawParams = new TreeMap<>(); 403 } 404 405 for ( JavaField field : javaClass.getFields() ) 406 { 407 rawParams.put( field.getName(), field ); 408 } 409 410 return rawParams; 411 } 412 413 protected Map<String, JavaClass> discoverClasses( final PluginToolsRequest request ) 414 { 415 return discoverClasses( request.getEncoding(), request.getProject() ); 416 } 417 418 protected Map<String, JavaClass> discoverClasses( final String encoding, final MavenProject project ) 419 { 420 List<File> sources = new ArrayList<>(); 421 422 for ( String source : project.getCompileSourceRoots() ) 423 { 424 sources.add( new File( source ) ); 425 } 426 427 // TODO be more dynamic 428 File generatedPlugin = new File( project.getBasedir(), "target/generated-sources/plugin" ); 429 if ( !project.getCompileSourceRoots().contains( generatedPlugin.getAbsolutePath() ) 430 && generatedPlugin.exists() ) 431 { 432 sources.add( generatedPlugin ); 433 } 434 435 return discoverClasses( encoding, sources, project.getArtifacts() ); 436 } 437 438 protected Map<String, JavaClass> discoverClasses( final String encoding, List<File> sourceDirectories, 439 Set<Artifact> artifacts ) 440 { 441 JavaProjectBuilder builder = new JavaProjectBuilder( new SortedClassLibraryBuilder() ); 442 builder.setEncoding( encoding ); 443 444 // Build isolated Classloader with only the artifacts of the project (none of this plugin) 445 List<URL> urls = new ArrayList<>( artifacts.size() ); 446 for ( Artifact artifact : artifacts ) 447 { 448 try 449 { 450 urls.add( artifact.getFile().toURI().toURL() ); 451 } 452 catch ( MalformedURLException e ) 453 { 454 // noop 455 } 456 } 457 builder.addClassLoader( new URLClassLoader( urls.toArray( new URL[0] ), ClassLoader.getSystemClassLoader() ) ); 458 459 for ( File source : sourceDirectories ) 460 { 461 builder.addSourceTree( source ); 462 } 463 464 Collection<JavaClass> javaClasses = builder.getClasses(); 465 466 if ( javaClasses == null || javaClasses.size() < 1 ) 467 { 468 return Collections.emptyMap(); 469 } 470 471 Map<String, JavaClass> javaClassMap = new HashMap<>( javaClasses.size() ); 472 473 for ( JavaClass javaClass : javaClasses ) 474 { 475 javaClassMap.put( javaClass.getFullyQualifiedName(), javaClass ); 476 } 477 478 return javaClassMap; 479 } 480 481 private List<MojoDescriptor> toMojoDescriptors( Map<String, MojoAnnotatedClass> mojoAnnotatedClasses, 482 PluginDescriptor pluginDescriptor ) 483 throws DuplicateParameterException, InvalidParameterException 484 { 485 List<MojoDescriptor> mojoDescriptors = new ArrayList<>( mojoAnnotatedClasses.size() ); 486 for ( MojoAnnotatedClass mojoAnnotatedClass : mojoAnnotatedClasses.values() ) 487 { 488 // no mojo so skip it 489 if ( mojoAnnotatedClass.getMojo() == null ) 490 { 491 continue; 492 } 493 494 ExtendedMojoDescriptor mojoDescriptor = new ExtendedMojoDescriptor(); 495 496 //mojoDescriptor.setRole( mojoAnnotatedClass.getClassName() ); 497 //mojoDescriptor.setRoleHint( "default" ); 498 mojoDescriptor.setImplementation( mojoAnnotatedClass.getClassName() ); 499 mojoDescriptor.setLanguage( "java" ); 500 501 MojoAnnotationContent mojo = mojoAnnotatedClass.getMojo(); 502 503 mojoDescriptor.setDescription( mojo.getDescription() ); 504 mojoDescriptor.setSince( mojo.getSince() ); 505 mojo.setDeprecated( mojo.getDeprecated() ); 506 507 mojoDescriptor.setProjectRequired( mojo.requiresProject() ); 508 509 mojoDescriptor.setRequiresReports( mojo.requiresReports() ); 510 511 mojoDescriptor.setComponentConfigurator( mojo.configurator() ); 512 513 mojoDescriptor.setInheritedByDefault( mojo.inheritByDefault() ); 514 515 mojoDescriptor.setInstantiationStrategy( mojo.instantiationStrategy().id() ); 516 517 mojoDescriptor.setAggregator( mojo.aggregator() ); 518 mojoDescriptor.setDependencyResolutionRequired( mojo.requiresDependencyResolution().id() ); 519 mojoDescriptor.setDependencyCollectionRequired( mojo.requiresDependencyCollection().id() ); 520 521 mojoDescriptor.setDirectInvocationOnly( mojo.requiresDirectInvocation() ); 522 mojoDescriptor.setDeprecated( mojo.getDeprecated() ); 523 mojoDescriptor.setThreadSafe( mojo.threadSafe() ); 524 525 ExecuteAnnotationContent execute = findExecuteInParentHierarchy( mojoAnnotatedClass, mojoAnnotatedClasses ); 526 if ( execute != null ) 527 { 528 mojoDescriptor.setExecuteGoal( execute.goal() ); 529 mojoDescriptor.setExecuteLifecycle( execute.lifecycle() ); 530 if ( execute.phase() != null ) 531 { 532 mojoDescriptor.setExecutePhase( execute.phase().id() ); 533 } 534 } 535 536 mojoDescriptor.setExecutionStrategy( mojo.executionStrategy() ); 537 // ??? 538 //mojoDescriptor.alwaysExecute(mojo.a) 539 540 mojoDescriptor.setGoal( mojo.name() ); 541 mojoDescriptor.setOnlineRequired( mojo.requiresOnline() ); 542 543 mojoDescriptor.setPhase( mojo.defaultPhase().id() ); 544 545 // Parameter annotations 546 Map<String, ParameterAnnotationContent> parameters = 547 getParametersParentHierarchy( mojoAnnotatedClass, new HashMap<String, ParameterAnnotationContent>(), 548 mojoAnnotatedClasses ); 549 550 for ( ParameterAnnotationContent parameterAnnotationContent : new TreeSet<>( parameters.values() ) ) 551 { 552 org.apache.maven.plugin.descriptor.Parameter parameter = 553 new org.apache.maven.plugin.descriptor.Parameter(); 554 String name = 555 StringUtils.isEmpty( parameterAnnotationContent.name() ) ? parameterAnnotationContent.getFieldName() 556 : parameterAnnotationContent.name(); 557 parameter.setName( name ); 558 parameter.setAlias( parameterAnnotationContent.alias() ); 559 parameter.setDefaultValue( parameterAnnotationContent.defaultValue() ); 560 parameter.setDeprecated( parameterAnnotationContent.getDeprecated() ); 561 parameter.setDescription( parameterAnnotationContent.getDescription() ); 562 parameter.setEditable( !parameterAnnotationContent.readonly() ); 563 String property = parameterAnnotationContent.property(); 564 if ( StringUtils.contains( property, '$' ) || StringUtils.contains( property, '{' ) 565 || StringUtils.contains( property, '}' ) ) 566 { 567 throw new InvalidParameterException( 568 "Invalid property for parameter '" + parameter.getName() + "', " + "forbidden characters ${}: " 569 + property, null ); 570 } 571 parameter.setExpression( StringUtils.isEmpty( property ) ? "" : "${" + property + "}" ); 572 parameter.setType( parameterAnnotationContent.getClassName() ); 573 parameter.setSince( parameterAnnotationContent.getSince() ); 574 parameter.setRequired( parameterAnnotationContent.required() ); 575 576 mojoDescriptor.addParameter( parameter ); 577 } 578 579 // Component annotations 580 Map<String, ComponentAnnotationContent> components = 581 getComponentsParentHierarchy( mojoAnnotatedClass, new HashMap<String, ComponentAnnotationContent>(), 582 mojoAnnotatedClasses ); 583 584 for ( ComponentAnnotationContent componentAnnotationContent : new TreeSet<>( components.values() ) ) 585 { 586 org.apache.maven.plugin.descriptor.Parameter parameter = 587 new org.apache.maven.plugin.descriptor.Parameter(); 588 parameter.setName( componentAnnotationContent.getFieldName() ); 589 590 // recognize Maven-injected objects as components annotations instead of parameters 591 String expression = PluginUtils.MAVEN_COMPONENTS.get( componentAnnotationContent.getRoleClassName() ); 592 if ( expression == null ) 593 { 594 // normal component 595 parameter.setRequirement( new Requirement( componentAnnotationContent.getRoleClassName(), 596 componentAnnotationContent.hint() ) ); 597 } 598 else 599 { 600 // not a component but a Maven object to be transformed into an expression/property: deprecated 601 getLogger().warn( "Deprecated @Component annotation for '" + parameter.getName() + "' field in " 602 + mojoAnnotatedClass.getClassName() 603 + ": replace with @Parameter( defaultValue = \"" + expression 604 + "\", readonly = true )" ); 605 parameter.setDefaultValue( expression ); 606 parameter.setType( componentAnnotationContent.getRoleClassName() ); 607 parameter.setRequired( true ); 608 } 609 parameter.setDeprecated( componentAnnotationContent.getDeprecated() ); 610 parameter.setSince( componentAnnotationContent.getSince() ); 611 612 // same behaviour as JavaMojoDescriptorExtractor 613 //parameter.setRequired( ... ); 614 parameter.setEditable( false ); 615 616 mojoDescriptor.addParameter( parameter ); 617 } 618 619 mojoDescriptor.setPluginDescriptor( pluginDescriptor ); 620 621 mojoDescriptors.add( mojoDescriptor ); 622 } 623 return mojoDescriptors; 624 } 625 626 protected ExecuteAnnotationContent findExecuteInParentHierarchy( MojoAnnotatedClass mojoAnnotatedClass, 627 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 628 { 629 if ( mojoAnnotatedClass.getExecute() != null ) 630 { 631 return mojoAnnotatedClass.getExecute(); 632 } 633 String parentClassName = mojoAnnotatedClass.getParentClassName(); 634 if ( StringUtils.isEmpty( parentClassName ) ) 635 { 636 return null; 637 } 638 MojoAnnotatedClass parent = mojoAnnotatedClasses.get( parentClassName ); 639 if ( parent == null ) 640 { 641 return null; 642 } 643 return findExecuteInParentHierarchy( parent, mojoAnnotatedClasses ); 644 } 645 646 647 protected Map<String, ParameterAnnotationContent> getParametersParentHierarchy( 648 MojoAnnotatedClass mojoAnnotatedClass, Map<String, ParameterAnnotationContent> parameters, 649 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 650 { 651 List<ParameterAnnotationContent> parameterAnnotationContents = new ArrayList<>(); 652 653 parameterAnnotationContents = 654 getParametersParent( mojoAnnotatedClass, parameterAnnotationContents, mojoAnnotatedClasses ); 655 656 // move to parent first to build the Map 657 Collections.reverse( parameterAnnotationContents ); 658 659 Map<String, ParameterAnnotationContent> map = new HashMap<>( parameterAnnotationContents.size() ); 660 661 for ( ParameterAnnotationContent parameterAnnotationContent : parameterAnnotationContents ) 662 { 663 map.put( parameterAnnotationContent.getFieldName(), parameterAnnotationContent ); 664 } 665 return map; 666 } 667 668 protected List<ParameterAnnotationContent> getParametersParent( MojoAnnotatedClass mojoAnnotatedClass, 669 List<ParameterAnnotationContent> parameterAnnotationContents, 670 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 671 { 672 parameterAnnotationContents.addAll( mojoAnnotatedClass.getParameters().values() ); 673 String parentClassName = mojoAnnotatedClass.getParentClassName(); 674 if ( parentClassName != null ) 675 { 676 MojoAnnotatedClass parent = mojoAnnotatedClasses.get( parentClassName ); 677 if ( parent != null ) 678 { 679 return getParametersParent( parent, parameterAnnotationContents, mojoAnnotatedClasses ); 680 } 681 } 682 return parameterAnnotationContents; 683 } 684 685 protected Map<String, ComponentAnnotationContent> getComponentsParentHierarchy( 686 MojoAnnotatedClass mojoAnnotatedClass, Map<String, ComponentAnnotationContent> components, 687 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 688 { 689 List<ComponentAnnotationContent> componentAnnotationContents = new ArrayList<>(); 690 691 componentAnnotationContents = 692 getComponentParent( mojoAnnotatedClass, componentAnnotationContents, mojoAnnotatedClasses ); 693 694 // move to parent first to build the Map 695 Collections.reverse( componentAnnotationContents ); 696 697 Map<String, ComponentAnnotationContent> map = new HashMap<>( componentAnnotationContents.size() ); 698 699 for ( ComponentAnnotationContent componentAnnotationContent : componentAnnotationContents ) 700 { 701 map.put( componentAnnotationContent.getFieldName(), componentAnnotationContent ); 702 } 703 return map; 704 } 705 706 protected List<ComponentAnnotationContent> getComponentParent( MojoAnnotatedClass mojoAnnotatedClass, 707 List<ComponentAnnotationContent> componentAnnotationContents, 708 Map<String, MojoAnnotatedClass> mojoAnnotatedClasses ) 709 { 710 componentAnnotationContents.addAll( mojoAnnotatedClass.getComponents().values() ); 711 String parentClassName = mojoAnnotatedClass.getParentClassName(); 712 if ( parentClassName != null ) 713 { 714 MojoAnnotatedClass parent = mojoAnnotatedClasses.get( parentClassName ); 715 if ( parent != null ) 716 { 717 return getComponentParent( parent, componentAnnotationContents, mojoAnnotatedClasses ); 718 } 719 } 720 return componentAnnotationContents; 721 } 722 723 protected MavenProject getFromProjectReferences( Artifact artifact, MavenProject project ) 724 { 725 if ( project.getProjectReferences() == null || project.getProjectReferences().isEmpty() ) 726 { 727 return null; 728 } 729 Collection<MavenProject> mavenProjects = project.getProjectReferences().values(); 730 for ( MavenProject mavenProject : mavenProjects ) 731 { 732 if ( Objects.equals( mavenProject.getId(), artifact.getId() ) ) 733 { 734 return mavenProject; 735 } 736 } 737 return null; 738 } 739 740}