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