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