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