001package org.apache.maven.tools.plugin.extractor.java; 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 com.thoughtworks.qdox.JavaDocBuilder; 023import com.thoughtworks.qdox.model.DocletTag; 024import com.thoughtworks.qdox.model.JavaClass; 025import com.thoughtworks.qdox.model.JavaField; 026import com.thoughtworks.qdox.model.Type; 027 028import org.apache.maven.plugin.descriptor.InvalidParameterException; 029import org.apache.maven.plugin.descriptor.InvalidPluginDescriptorException; 030import org.apache.maven.plugin.descriptor.MojoDescriptor; 031import org.apache.maven.plugin.descriptor.Parameter; 032import org.apache.maven.plugin.descriptor.Requirement; 033import org.apache.maven.project.MavenProject; 034import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; 035import org.apache.maven.tools.plugin.PluginToolsRequest; 036import org.apache.maven.tools.plugin.extractor.MojoDescriptorExtractor; 037import org.apache.maven.tools.plugin.extractor.ExtractionException; 038import org.apache.maven.tools.plugin.util.PluginUtils; 039 040import org.codehaus.plexus.component.annotations.Component; 041import org.codehaus.plexus.logging.AbstractLogEnabled; 042import org.codehaus.plexus.util.StringUtils; 043 044import java.io.File; 045import java.util.ArrayList; 046import java.util.List; 047import java.util.Map; 048import java.util.TreeMap; 049 050/** 051 * Extracts Mojo descriptors from <a href="http://java.sun.com/">Java</a> sources. 052 * <br/> 053 * For more information about the usage tag, have a look to: 054 * <a href="http://maven.apache.org/developers/mojo-api-specification.html"> 055 * http://maven.apache.org/developers/mojo-api-specification.html</a> 056 * 057 * @todo need to add validation directives so that systems embedding maven2 can 058 * get validation directives to help users in IDEs. 059 * @version $Id: JavaMojoDescriptorExtractor.html 907947 2014-05-03 19:43:49Z hboutemy $ 060 * @see org.apache.maven.plugin.descriptor.MojoDescriptor 061 */ 062@Component( role = MojoDescriptorExtractor.class, hint = "java" ) 063public class JavaMojoDescriptorExtractor 064 extends AbstractLogEnabled 065 implements MojoDescriptorExtractor, JavaMojoAnnotation 066{ 067 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#INSTANTIATION_STRATEGY} instead of. */ 068 public static final String MAVEN_PLUGIN_INSTANTIATION = JavaMojoAnnotation.INSTANTIATION_STRATEGY; 069 070 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#CONFIGURATOR} instead of. */ 071 public static final String CONFIGURATOR = JavaMojoAnnotation.CONFIGURATOR; 072 073 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER} instead of. */ 074 public static final String PARAMETER = JavaMojoAnnotation.PARAMETER; 075 076 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER_EXPRESSION} instead of. */ 077 public static final String PARAMETER_EXPRESSION = JavaMojoAnnotation.PARAMETER_EXPRESSION; 078 079 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER_DEFAULT_VALUE} instead of. */ 080 public static final String PARAMETER_DEFAULT_VALUE = JavaMojoAnnotation.PARAMETER_DEFAULT_VALUE; 081 082 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER_ALIAS} instead of. */ 083 public static final String PARAMETER_ALIAS = JavaMojoAnnotation.PARAMETER_ALIAS; 084 085 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#SINCE} instead of. */ 086 public static final String SINCE = JavaMojoAnnotation.SINCE; 087 088 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PARAMETER_IMPLEMENTATION} instead of. */ 089 public static final String PARAMETER_IMPLEMENTATION = JavaMojoAnnotation.PARAMETER_IMPLEMENTATION; 090 091 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRED} instead of. */ 092 public static final String REQUIRED = JavaMojoAnnotation.REQUIRED; 093 094 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#DEPRECATED} instead of. */ 095 public static final String DEPRECATED = JavaMojoAnnotation.DEPRECATED; 096 097 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#READONLY} instead of. */ 098 public static final String READONLY = JavaMojoAnnotation.READONLY; 099 100 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#GOAL} instead of. */ 101 public static final String GOAL = JavaMojoAnnotation.GOAL; 102 103 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#PHASE} instead of. */ 104 public static final String PHASE = JavaMojoAnnotation.PHASE; 105 106 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#EXECUTE} instead of. */ 107 public static final String EXECUTE = JavaMojoAnnotation.EXECUTE; 108 109 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#EXECUTE_LIFECYCLE} instead of. */ 110 public static final String EXECUTE_LIFECYCLE = JavaMojoAnnotation.EXECUTE_LIFECYCLE; 111 112 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#EXECUTE_PHASE} instead of. */ 113 public static final String EXECUTE_PHASE = JavaMojoAnnotation.EXECUTE_PHASE; 114 115 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#EXECUTE_GOAL} instead of. */ 116 public static final String EXECUTE_GOAL = JavaMojoAnnotation.EXECUTE_GOAL; 117 118 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#DESCRIPTION} instead of. */ 119 public static final String GOAL_DESCRIPTION = JavaMojoAnnotation.DESCRIPTION; 120 121 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_DEPENDENCY_RESOLUTION} instead of. */ 122 public static final String GOAL_REQUIRES_DEPENDENCY_RESOLUTION = JavaMojoAnnotation.REQUIRES_DEPENDENCY_RESOLUTION; 123 124 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_PROJECT} instead of. */ 125 public static final String GOAL_REQUIRES_PROJECT = JavaMojoAnnotation.REQUIRES_PROJECT; 126 127 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_REPORTS} instead of. */ 128 public static final String GOAL_REQUIRES_REPORTS = JavaMojoAnnotation.REQUIRES_REPORTS; 129 130 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#AGGREGATOR} instead of. */ 131 public static final String GOAL_IS_AGGREGATOR = JavaMojoAnnotation.AGGREGATOR; 132 133 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_ONLINE} instead of. */ 134 public static final String GOAL_REQUIRES_ONLINE = JavaMojoAnnotation.REQUIRES_ONLINE; 135 136 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#INHERIT_BY_DEFAULT} instead of. */ 137 public static final String GOAL_INHERIT_BY_DEFAULT = JavaMojoAnnotation.INHERIT_BY_DEFAULT; 138 139 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#MULTI_EXECUTION_STRATEGY} instead of. */ 140 public static final String GOAL_MULTI_EXECUTION_STRATEGY = JavaMojoAnnotation.MULTI_EXECUTION_STRATEGY; 141 142 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#REQUIRES_DIRECT_INVOCATION} instead of. */ 143 public static final String GOAL_REQUIRES_DIRECT_INVOCATION = JavaMojoAnnotation.REQUIRES_DIRECT_INVOCATION; 144 145 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#COMPONENT} instead of. */ 146 public static final String COMPONENT = JavaMojoAnnotation.COMPONENT; 147 148 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#COMPONENT_ROLE} instead of. */ 149 public static final String COMPONENT_ROLE = JavaMojoAnnotation.COMPONENT_ROLE; 150 151 /** @deprecated since 2.4, use {@link JavaMojoAnnotation#COMPONENT_ROLEHINT} instead of. */ 152 public static final String COMPONENT_ROLEHINT = JavaMojoAnnotation.COMPONENT_ROLEHINT; 153 154 /** 155 * @param parameter not null 156 * @param i positive number 157 * @throws InvalidParameterException if any 158 */ 159 protected void validateParameter( Parameter parameter, int i ) 160 throws InvalidParameterException 161 { 162 // TODO: remove when backward compatibility is no longer an issue. 163 String name = parameter.getName(); 164 165 if ( name == null ) 166 { 167 throw new InvalidParameterException( "name", i ); 168 } 169 170 // TODO: remove when backward compatibility is no longer an issue. 171 String type = parameter.getType(); 172 173 if ( type == null ) 174 { 175 throw new InvalidParameterException( "type", i ); 176 } 177 178 // TODO: remove when backward compatibility is no longer an issue. 179 String description = parameter.getDescription(); 180 181 if ( description == null ) 182 { 183 throw new InvalidParameterException( "description", i ); 184 } 185 } 186 187 // ---------------------------------------------------------------------- 188 // Mojo descriptor creation from @tags 189 // ---------------------------------------------------------------------- 190 191 /** 192 * @param javaClass not null 193 * @return a mojo descriptor 194 * @throws InvalidPluginDescriptorException if any 195 */ 196 protected MojoDescriptor createMojoDescriptor( JavaClass javaClass ) 197 throws InvalidPluginDescriptorException 198 { 199 ExtendedMojoDescriptor mojoDescriptor = new ExtendedMojoDescriptor(); 200 mojoDescriptor.setLanguage( "java" ); 201 mojoDescriptor.setImplementation( javaClass.getFullyQualifiedName() ); 202 mojoDescriptor.setDescription( javaClass.getComment() ); 203 204 // ---------------------------------------------------------------------- 205 // Mojo annotations in alphabetical order 206 // ---------------------------------------------------------------------- 207 208 // Aggregator flag 209 DocletTag aggregator = findInClassHierarchy( javaClass, JavaMojoAnnotation.AGGREGATOR ); 210 if ( aggregator != null ) 211 { 212 mojoDescriptor.setAggregator( true ); 213 } 214 215 // Configurator hint 216 DocletTag configurator = findInClassHierarchy( javaClass, JavaMojoAnnotation.CONFIGURATOR ); 217 if ( configurator != null ) 218 { 219 mojoDescriptor.setComponentConfigurator( configurator.getValue() ); 220 } 221 222 // Additional phase to execute first 223 DocletTag execute = findInClassHierarchy( javaClass, JavaMojoAnnotation.EXECUTE ); 224 if ( execute != null ) 225 { 226 String executePhase = execute.getNamedParameter( JavaMojoAnnotation.EXECUTE_PHASE ); 227 String executeGoal = execute.getNamedParameter( JavaMojoAnnotation.EXECUTE_GOAL ); 228 229 if ( executePhase == null && executeGoal == null ) 230 { 231 throw new InvalidPluginDescriptorException( javaClass.getFullyQualifiedName() 232 + ": @execute tag requires either a 'phase' or 'goal' parameter" ); 233 } 234 else if ( executePhase != null && executeGoal != null ) 235 { 236 throw new InvalidPluginDescriptorException( javaClass.getFullyQualifiedName() 237 + ": @execute tag can have only one of a 'phase' or 'goal' parameter" ); 238 } 239 mojoDescriptor.setExecutePhase( executePhase ); 240 mojoDescriptor.setExecuteGoal( executeGoal ); 241 242 String lifecycle = execute.getNamedParameter( JavaMojoAnnotation.EXECUTE_LIFECYCLE ); 243 if ( lifecycle != null ) 244 { 245 mojoDescriptor.setExecuteLifecycle( lifecycle ); 246 if ( mojoDescriptor.getExecuteGoal() != null ) 247 { 248 throw new InvalidPluginDescriptorException( javaClass.getFullyQualifiedName() 249 + ": @execute lifecycle requires a phase instead of a goal" ); 250 } 251 } 252 } 253 254 // Goal name 255 DocletTag goal = findInClassHierarchy( javaClass, JavaMojoAnnotation.GOAL ); 256 if ( goal != null ) 257 { 258 mojoDescriptor.setGoal( goal.getValue() ); 259 } 260 261 // inheritByDefault flag 262 boolean value = 263 getBooleanTagValue( javaClass, JavaMojoAnnotation.INHERIT_BY_DEFAULT, 264 mojoDescriptor.isInheritedByDefault() ); 265 mojoDescriptor.setInheritedByDefault( value ); 266 267 // instantiationStrategy 268 DocletTag tag = findInClassHierarchy( javaClass, JavaMojoAnnotation.INSTANTIATION_STRATEGY ); 269 if ( tag != null ) 270 { 271 mojoDescriptor.setInstantiationStrategy( tag.getValue() ); 272 } 273 274 // executionStrategy (and deprecated @attainAlways) 275 tag = findInClassHierarchy( javaClass, JavaMojoAnnotation.MULTI_EXECUTION_STRATEGY ); 276 if ( tag != null ) 277 { 278 getLogger().warn( "@" + JavaMojoAnnotation.MULTI_EXECUTION_STRATEGY + " in " 279 + javaClass.getFullyQualifiedName() + " is deprecated: please use '@" 280 + JavaMojoAnnotation.EXECUTION_STATEGY + " always' instead." ); 281 mojoDescriptor.setExecutionStrategy( MojoDescriptor.MULTI_PASS_EXEC_STRATEGY ); 282 } 283 else 284 { 285 mojoDescriptor.setExecutionStrategy( MojoDescriptor.SINGLE_PASS_EXEC_STRATEGY ); 286 } 287 tag = findInClassHierarchy( javaClass, JavaMojoAnnotation.EXECUTION_STATEGY ); 288 if ( tag != null ) 289 { 290 mojoDescriptor.setExecutionStrategy( tag.getValue() ); 291 } 292 293 // Phase name 294 DocletTag phase = findInClassHierarchy( javaClass, JavaMojoAnnotation.PHASE ); 295 if ( phase != null ) 296 { 297 mojoDescriptor.setPhase( phase.getValue() ); 298 } 299 300 // Dependency resolution flag 301 DocletTag requiresDependencyResolution = 302 findInClassHierarchy( javaClass, JavaMojoAnnotation.REQUIRES_DEPENDENCY_RESOLUTION ); 303 if ( requiresDependencyResolution != null ) 304 { 305 String v = requiresDependencyResolution.getValue(); 306 307 if ( StringUtils.isEmpty( v ) ) 308 { 309 v = "runtime"; 310 } 311 312 mojoDescriptor.setDependencyResolutionRequired( v ); 313 } 314 315 // Dependency collection flag 316 DocletTag requiresDependencyCollection = 317 findInClassHierarchy( javaClass, JavaMojoAnnotation.REQUIRES_DEPENDENCY_COLLECTION ); 318 if ( requiresDependencyCollection != null ) 319 { 320 String v = requiresDependencyCollection.getValue(); 321 322 if ( StringUtils.isEmpty( v ) ) 323 { 324 v = "runtime"; 325 } 326 327 mojoDescriptor.setDependencyCollectionRequired( v ); 328 } 329 330 // requiresDirectInvocation flag 331 value = 332 getBooleanTagValue( javaClass, JavaMojoAnnotation.REQUIRES_DIRECT_INVOCATION, 333 mojoDescriptor.isDirectInvocationOnly() ); 334 mojoDescriptor.setDirectInvocationOnly( value ); 335 336 // Online flag 337 value = 338 getBooleanTagValue( javaClass, JavaMojoAnnotation.REQUIRES_ONLINE, mojoDescriptor.isOnlineRequired() ); 339 mojoDescriptor.setOnlineRequired( value ); 340 341 // Project flag 342 value = 343 getBooleanTagValue( javaClass, JavaMojoAnnotation.REQUIRES_PROJECT, mojoDescriptor.isProjectRequired() ); 344 mojoDescriptor.setProjectRequired( value ); 345 346 // requiresReports flag 347 value = 348 getBooleanTagValue( javaClass, JavaMojoAnnotation.REQUIRES_REPORTS, mojoDescriptor.isRequiresReports() ); 349 mojoDescriptor.setRequiresReports( value ); 350 351 // ---------------------------------------------------------------------- 352 // Javadoc annotations in alphabetical order 353 // ---------------------------------------------------------------------- 354 355 // Deprecation hint 356 DocletTag deprecated = javaClass.getTagByName( JavaMojoAnnotation.DEPRECATED ); 357 if ( deprecated != null ) 358 { 359 mojoDescriptor.setDeprecated( deprecated.getValue() ); 360 } 361 362 // What version it was introduced in 363 DocletTag since = findInClassHierarchy( javaClass, JavaMojoAnnotation.SINCE ); 364 if ( since != null ) 365 { 366 mojoDescriptor.setSince( since.getValue() ); 367 } 368 369 // Thread-safe mojo 370 371 value = getBooleanTagValue( javaClass, JavaMojoAnnotation.THREAD_SAFE, true, mojoDescriptor.isThreadSafe() ); 372 mojoDescriptor.setThreadSafe( value ); 373 374 extractParameters( mojoDescriptor, javaClass ); 375 376 return mojoDescriptor; 377 } 378 379 /** 380 * @param javaClass not null 381 * @param tagName not null 382 * @param defaultValue the wanted default value 383 * @return the boolean value of the given tagName 384 * @see #findInClassHierarchy(JavaClass, String) 385 */ 386 private static boolean getBooleanTagValue( JavaClass javaClass, String tagName, boolean defaultValue ) 387 { 388 DocletTag tag = findInClassHierarchy( javaClass, tagName ); 389 390 if ( tag != null ) 391 { 392 String value = tag.getValue(); 393 394 if ( StringUtils.isNotEmpty( value ) ) 395 { 396 defaultValue = Boolean.valueOf( value ).booleanValue(); 397 } 398 } 399 return defaultValue; 400 } 401 402 /** 403 * @param javaClass not null 404 * @param tagName not null 405 * @param defaultForTag The wanted default value when only the tagname is present 406 * @param defaultValue the wanted default value when the tag is not specified 407 * @return the boolean value of the given tagName 408 * @see #findInClassHierarchy(JavaClass, String) 409 */ 410 private static boolean getBooleanTagValue( JavaClass javaClass, String tagName, boolean defaultForTag, 411 boolean defaultValue ) 412 { 413 DocletTag tag = findInClassHierarchy( javaClass, tagName ); 414 415 if ( tag != null ) 416 { 417 String value = tag.getValue(); 418 419 if ( StringUtils.isNotEmpty( value ) ) 420 { 421 return Boolean.valueOf( value ).booleanValue(); 422 } 423 else 424 { 425 return defaultForTag; 426 } 427 } 428 return defaultValue; 429 } 430 431 /** 432 * @param javaClass not null 433 * @param tagName not null 434 * @return docletTag instance 435 */ 436 private static DocletTag findInClassHierarchy( JavaClass javaClass, String tagName ) 437 { 438 DocletTag tag = javaClass.getTagByName( tagName ); 439 440 if ( tag == null ) 441 { 442 JavaClass superClass = javaClass.getSuperJavaClass(); 443 444 if ( superClass != null ) 445 { 446 tag = findInClassHierarchy( superClass, tagName ); 447 } 448 } 449 450 return tag; 451 } 452 453 /** 454 * @param mojoDescriptor not null 455 * @param javaClass not null 456 * @throws InvalidPluginDescriptorException if any 457 */ 458 private void extractParameters( MojoDescriptor mojoDescriptor, JavaClass javaClass ) 459 throws InvalidPluginDescriptorException 460 { 461 // --------------------------------------------------------------------------------- 462 // We're resolving class-level, ancestor-class-field, local-class-field order here. 463 // --------------------------------------------------------------------------------- 464 465 Map<String, JavaField> rawParams = extractFieldParameterTags( javaClass ); 466 467 for ( Map.Entry<String, JavaField> entry : rawParams.entrySet() ) 468 { 469 JavaField field = entry.getValue(); 470 471 Type type = field.getType(); 472 473 Parameter pd = new Parameter(); 474 475 pd.setName( entry.getKey() ); 476 477 if ( !type.isArray() ) 478 { 479 pd.setType( type.getValue() ); 480 } 481 else 482 { 483 StringBuilder value = new StringBuilder( type.getValue() ); 484 485 int remaining = type.getDimensions(); 486 487 while ( remaining-- > 0 ) 488 { 489 value.append( "[]" ); 490 } 491 492 pd.setType( value.toString() ); 493 } 494 495 pd.setDescription( field.getComment() ); 496 497 DocletTag deprecationTag = field.getTagByName( JavaMojoAnnotation.DEPRECATED ); 498 499 if ( deprecationTag != null ) 500 { 501 pd.setDeprecated( deprecationTag.getValue() ); 502 } 503 504 DocletTag sinceTag = field.getTagByName( JavaMojoAnnotation.SINCE ); 505 if ( sinceTag != null ) 506 { 507 pd.setSince( sinceTag.getValue() ); 508 } 509 510 DocletTag componentTag = field.getTagByName( JavaMojoAnnotation.COMPONENT ); 511 512 if ( componentTag != null ) 513 { 514 // Component tag 515 String role = componentTag.getNamedParameter( JavaMojoAnnotation.COMPONENT_ROLE ); 516 517 if ( role == null ) 518 { 519 role = field.getType().toString(); 520 } 521 522 String roleHint = componentTag.getNamedParameter( JavaMojoAnnotation.COMPONENT_ROLEHINT ); 523 524 if ( roleHint == null ) 525 { 526 // support alternate syntax for better compatibility with the Plexus CDC. 527 roleHint = componentTag.getNamedParameter( "role-hint" ); 528 } 529 530 // recognize Maven-injected objects as components annotations instead of parameters 531 String expression = PluginUtils.MAVEN_COMPONENTS.get( role ); 532 533 if ( expression == null ) 534 { 535 // normal component 536 pd.setRequirement( new Requirement( role, roleHint ) ); 537 } 538 else 539 { 540 // not a component but a Maven object to be transformed into an expression/property 541 getLogger().warn( "Deprecated @Component for " + pd.getName() + " field in " 542 + javaClass.getFullyQualifiedName() + ": replace with @Parameter( name = \"" 543 + expression + "\", readonly = true )" ); 544 pd.setDefaultValue( expression ); 545 pd.setType( role ); 546 pd.setRequired( true ); 547 } 548 549 pd.setEditable( false ); 550 /* TODO: or better like this? Need @component fields be editable for the user? 551 pd.setEditable( field.getTagByName( READONLY ) == null ); 552 */ 553 } 554 else 555 { 556 // Parameter tag 557 DocletTag parameter = field.getTagByName( JavaMojoAnnotation.PARAMETER ); 558 559 pd.setRequired( field.getTagByName( JavaMojoAnnotation.REQUIRED ) != null ); 560 561 pd.setEditable( field.getTagByName( JavaMojoAnnotation.READONLY ) == null ); 562 563 String name = parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_NAME ); 564 565 if ( !StringUtils.isEmpty( name ) ) 566 { 567 pd.setName( name ); 568 } 569 570 String alias = parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_ALIAS ); 571 572 if ( !StringUtils.isEmpty( alias ) ) 573 { 574 pd.setAlias( alias ); 575 } 576 577 String expression = parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_EXPRESSION ); 578 String property = parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_PROPERTY ); 579 580 if ( StringUtils.isNotEmpty( expression ) && StringUtils.isNotEmpty( property ) ) 581 { 582 getLogger().error( javaClass.getFullyQualifiedName() + "#" + field.getName() + ":" ); 583 getLogger().error( " Cannot use both:" ); 584 getLogger().error( " @parameter expression=\"${property}\"" ); 585 getLogger().error( " and" ); 586 getLogger().error( " @parameter property=\"property\"" ); 587 getLogger().error( " Second syntax is preferred." ); 588 throw new InvalidParameterException( javaClass.getFullyQualifiedName() + "#" + field.getName() 589 + ": cannot" + " use both @parameter expression and property", null ); 590 } 591 592 if ( StringUtils.isNotEmpty( expression ) ) 593 { 594 getLogger().warn( javaClass.getFullyQualifiedName() + "#" + field.getName() + ":" ); 595 getLogger().warn( " The syntax" ); 596 getLogger().warn( " @parameter expression=\"${property}\"" ); 597 getLogger().warn( " is deprecated, please use" ); 598 getLogger().warn( " @parameter property=\"property\"" ); 599 getLogger().warn( " instead." ); 600 601 } 602 else if ( StringUtils.isNotEmpty( property ) ) 603 { 604 expression = "${" + property + "}"; 605 } 606 607 pd.setExpression( expression ); 608 609 if ( StringUtils.isNotEmpty( expression ) && expression.startsWith( "${component." ) ) 610 { 611 getLogger().warn( javaClass.getFullyQualifiedName() + "#" + field.getName() + ":" ); 612 getLogger().warn( " The syntax" ); 613 getLogger().warn( " @parameter expression=\"${component.<role>#<roleHint>}\"" ); 614 getLogger().warn( " is deprecated, please use" ); 615 getLogger().warn( " @component role=\"<role>\" roleHint=\"<roleHint>\"" ); 616 getLogger().warn( " instead." ); 617 } 618 619 if ( "${reports}".equals( pd.getExpression() ) ) 620 { 621 mojoDescriptor.setRequiresReports( true ); 622 } 623 624 pd.setDefaultValue( parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_DEFAULT_VALUE ) ); 625 626 pd.setImplementation( parameter.getNamedParameter( JavaMojoAnnotation.PARAMETER_IMPLEMENTATION ) ); 627 } 628 629 mojoDescriptor.addParameter( pd ); 630 } 631 } 632 633 /** 634 * extract fields that are either parameters or components. 635 * 636 * @param javaClass not null 637 * @return map with Mojo parameters names as keys 638 */ 639 private Map<String, JavaField> extractFieldParameterTags( JavaClass javaClass ) 640 { 641 Map<String, JavaField> rawParams; 642 643 // we have to add the parent fields first, so that they will be overwritten by the local fields if 644 // that actually happens... 645 JavaClass superClass = javaClass.getSuperJavaClass(); 646 647 if ( superClass != null ) 648 { 649 rawParams = extractFieldParameterTags( superClass ); 650 } 651 else 652 { 653 rawParams = new TreeMap<String, JavaField>(); 654 } 655 656 JavaField[] classFields = javaClass.getFields(); 657 658 if ( classFields != null ) 659 { 660 for ( JavaField field : classFields ) 661 { 662 if ( field.getTagByName( JavaMojoAnnotation.PARAMETER ) != null 663 || field.getTagByName( JavaMojoAnnotation.COMPONENT ) != null ) 664 { 665 rawParams.put( field.getName(), field ); 666 } 667 } 668 } 669 return rawParams; 670 } 671 672 /** {@inheritDoc} */ 673 public List<MojoDescriptor> execute( PluginToolsRequest request ) 674 throws ExtractionException, InvalidPluginDescriptorException 675 { 676 JavaClass[] javaClasses = discoverClasses( request ); 677 678 List<MojoDescriptor> descriptors = new ArrayList<MojoDescriptor>(); 679 680 for ( JavaClass javaClass : javaClasses ) 681 { 682 DocletTag tag = javaClass.getTagByName( GOAL ); 683 684 if ( tag != null ) 685 { 686 MojoDescriptor mojoDescriptor = createMojoDescriptor( javaClass ); 687 mojoDescriptor.setPluginDescriptor( request.getPluginDescriptor() ); 688 689 // Validate the descriptor as best we can before allowing it to be processed. 690 validate( mojoDescriptor ); 691 692 descriptors.add( mojoDescriptor ); 693 } 694 } 695 696 return descriptors; 697 } 698 699 /** 700 * @param request The plugin request. 701 * @return an array of java class 702 */ 703 @SuppressWarnings( "unchecked" ) 704 protected JavaClass[] discoverClasses( final PluginToolsRequest request ) 705 { 706 JavaDocBuilder builder = new JavaDocBuilder(); 707 builder.setEncoding( request.getEncoding() ); 708 709 MavenProject project = request.getProject(); 710 711 for ( String source : (List<String>) project.getCompileSourceRoots() ) 712 { 713 builder.addSourceTree( new File( source ) ); 714 } 715 716 // TODO be more dynamic 717 File generatedPlugin = new File( project.getBasedir(), "target/generated-sources/plugin" ); 718 if ( !project.getCompileSourceRoots().contains( generatedPlugin.getAbsolutePath() ) ) 719 { 720 builder.addSourceTree( generatedPlugin ); 721 } 722 723 return builder.getClasses(); 724 } 725 726 /** 727 * @param mojoDescriptor not null 728 * @throws InvalidParameterException if any 729 */ 730 protected void validate( MojoDescriptor mojoDescriptor ) 731 throws InvalidParameterException 732 { 733 @SuppressWarnings( "unchecked" ) 734 List<Parameter> parameters = mojoDescriptor.getParameters(); 735 736 if ( parameters != null ) 737 { 738 for ( int j = 0; j < parameters.size(); j++ ) 739 { 740 validateParameter( parameters.get( j ), j ); 741 } 742 } 743 } 744}