001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.tools.plugin.generator; 020 021import java.io.File; 022import java.io.IOException; 023import java.io.OutputStreamWriter; 024import java.io.Writer; 025import java.net.URI; 026import java.util.LinkedHashMap; 027import java.util.LinkedHashSet; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031 032import org.apache.maven.plugin.descriptor.MojoDescriptor; 033import org.apache.maven.plugin.descriptor.Parameter; 034import org.apache.maven.plugin.descriptor.PluginDescriptor; 035import org.apache.maven.plugin.descriptor.Requirement; 036import org.apache.maven.project.MavenProject; 037import org.apache.maven.tools.plugin.ExtendedMojoDescriptor; 038import org.apache.maven.tools.plugin.PluginDescriptorHelper; 039import org.apache.maven.tools.plugin.PluginToolsRequest; 040import org.apache.maven.tools.plugin.javadoc.JavadocLinkGenerator; 041import org.apache.maven.tools.plugin.util.PluginUtils; 042import org.codehaus.plexus.util.StringUtils; 043import org.codehaus.plexus.util.io.CachingOutputStream; 044import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter; 045import org.codehaus.plexus.util.xml.XMLWriter; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049import static java.nio.charset.StandardCharsets.UTF_8; 050 051/** 052 * Serializes 053 * <ol> 054 * <li>a standard <a href="/ref/current/maven-plugin-api/plugin.html">Maven Plugin Descriptor XML file</a></li> 055 * <li>a descriptor containing a limited set of elements for {@link PluginHelpGenerator}</li> 056 * <li>an enhanced descriptor containing HTML values for some elements (instead of plain text as for the other two) 057 * for {@code org.apache.maven.plugin.plugin.report.GoalRenderer}</li> 058 * </ol> 059 * from a given in-memory descriptor. The in-memory descriptor acting as source is supposed to contain XHTML values 060 * for description elements. 061 */ 062public class PluginDescriptorFilesGenerator implements Generator { 063 private static final Logger LOG = LoggerFactory.getLogger(PluginDescriptorFilesGenerator.class); 064 065 /** 066 * The type of the plugin descriptor file 067 */ 068 enum DescriptorType { 069 STANDARD, 070 LIMITED_FOR_HELP_MOJO, 071 XHTML 072 } 073 074 @Override 075 public void execute(File destinationDirectory, PluginToolsRequest request) throws GeneratorException { 076 try { 077 // write standard plugin.xml descriptor 078 File f = new File(destinationDirectory, "plugin.xml"); 079 writeDescriptor(f, request, DescriptorType.STANDARD); 080 081 // write plugin-help.xml help-descriptor (containing only a limited set of attributes) 082 MavenProject mavenProject = request.getProject(); 083 f = new File(destinationDirectory, PluginHelpGenerator.getPluginHelpPath(mavenProject)); 084 writeDescriptor(f, request, DescriptorType.LIMITED_FOR_HELP_MOJO); 085 086 // write enhanced plugin-enhanced.xml descriptor (containing some XHTML values) 087 f = getEnhancedDescriptorFilePath(mavenProject); 088 writeDescriptor(f, request, DescriptorType.XHTML); 089 } catch (IOException e) { 090 throw new GeneratorException(e.getMessage(), e); 091 } 092 } 093 094 public static File getEnhancedDescriptorFilePath(MavenProject project) { 095 return new File(project.getBuild().getDirectory(), "plugin-enhanced.xml"); 096 } 097 098 private String getVersion() { 099 Package p = this.getClass().getPackage(); 100 String version = (p == null) ? null : p.getSpecificationVersion(); 101 return (version == null) ? "SNAPSHOT" : version; 102 } 103 104 public void writeDescriptor(File destinationFile, PluginToolsRequest request, DescriptorType type) 105 throws IOException { 106 PluginDescriptor pluginDescriptor = request.getPluginDescriptor(); 107 108 if (!destinationFile.getParentFile().exists()) { 109 destinationFile.getParentFile().mkdirs(); 110 } 111 112 String apiVersion = request.getPluginDescriptor().getRequiredMavenVersion(); 113 boolean isV4 = apiVersion != null && apiVersion.startsWith("4."); 114 115 try (Writer writer = new OutputStreamWriter(new CachingOutputStream(destinationFile), UTF_8)) { 116 XMLWriter w = new PrettyPrintXMLWriter(writer, UTF_8.name(), null); 117 118 final String additionalInfo; 119 switch (type) { 120 case LIMITED_FOR_HELP_MOJO: 121 additionalInfo = " (for help mojo with limited elements)"; 122 break; 123 case XHTML: 124 additionalInfo = " (enhanced XHTML version (used for plugin:report))"; 125 break; 126 default: 127 additionalInfo = ""; 128 break; 129 } 130 w.writeMarkup("\n<!-- Generated by maven-plugin-tools " + getVersion() + additionalInfo + "-->\n\n"); 131 132 w.startElement("plugin"); 133 if (isV4) { 134 w.addAttribute("xmlns", "http://maven.apache.org/PLUGIN/2.0.0"); 135 w.addAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); 136 w.addAttribute( 137 "xsi:location", 138 "http://maven.apache.org/PLUGIN/2.0.0 https://maven.apache.org/xsd/plugin-2.0.0.xsd"); 139 } 140 141 GeneratorUtils.element(w, "name", pluginDescriptor.getName()); 142 143 GeneratorUtils.element(w, "description", pluginDescriptor.getDescription()); 144 145 GeneratorUtils.element(w, "groupId", pluginDescriptor.getGroupId()); 146 147 GeneratorUtils.element(w, "artifactId", pluginDescriptor.getArtifactId()); 148 149 GeneratorUtils.element(w, "version", pluginDescriptor.getVersion()); 150 151 GeneratorUtils.element(w, "goalPrefix", pluginDescriptor.getGoalPrefix()); 152 153 if (type != DescriptorType.LIMITED_FOR_HELP_MOJO) { 154 GeneratorUtils.element(w, "isolatedRealm", String.valueOf(pluginDescriptor.isIsolatedRealm())); 155 156 GeneratorUtils.element( 157 w, "inheritedByDefault", String.valueOf(pluginDescriptor.isInheritedByDefault())); 158 159 if (StringUtils.isNotBlank(PluginDescriptorHelper.getRequiredJavaVersion(pluginDescriptor))) { 160 GeneratorUtils.element( 161 w, "requiredJavaVersion", PluginDescriptorHelper.getRequiredJavaVersion(pluginDescriptor)); 162 } 163 if (StringUtils.isNotBlank(pluginDescriptor.getRequiredMavenVersion())) { 164 GeneratorUtils.element(w, "requiredMavenVersion", pluginDescriptor.getRequiredMavenVersion()); 165 } 166 } 167 168 w.startElement("mojos"); 169 170 final JavadocLinkGenerator javadocLinkGenerator; 171 if (request.getInternalJavadocBaseUrl() != null 172 || (request.getExternalJavadocBaseUrls() != null 173 && !request.getExternalJavadocBaseUrls().isEmpty())) { 174 javadocLinkGenerator = new JavadocLinkGenerator( 175 request.getInternalJavadocBaseUrl(), 176 request.getInternalJavadocVersion(), 177 request.getExternalJavadocBaseUrls(), 178 request.getSettings()); 179 } else { 180 javadocLinkGenerator = null; 181 } 182 if (pluginDescriptor.getMojos() != null) { 183 List<MojoDescriptor> descriptors = pluginDescriptor.getMojos(); 184 185 PluginUtils.sortMojos(descriptors); 186 187 for (MojoDescriptor descriptor : descriptors) { 188 processMojoDescriptor(descriptor, w, type, javadocLinkGenerator, isV4); 189 } 190 } 191 192 w.endElement(); 193 194 if (!isV4 && type != DescriptorType.LIMITED_FOR_HELP_MOJO) { 195 GeneratorUtils.writeDependencies(w, pluginDescriptor); 196 } 197 198 w.endElement(); 199 200 writer.flush(); 201 } 202 } 203 204 /** 205 * @param type 206 * @param containsXhtmlValue 207 * @param text 208 * @return the normalized text value (i.e. potentially converted to XHTML) 209 */ 210 private static String getTextValue(DescriptorType type, boolean containsXhtmlValue, String text) { 211 final String xhtmlText; 212 if (!containsXhtmlValue) // text comes from legacy extractor 213 { 214 xhtmlText = GeneratorUtils.makeHtmlValid(text); 215 } else { 216 xhtmlText = text; 217 } 218 if (type != DescriptorType.XHTML) { 219 return new HtmlToPlainTextConverter().convert(text); 220 } else { 221 return xhtmlText; 222 } 223 } 224 225 @SuppressWarnings("deprecation") 226 protected void processMojoDescriptor( 227 MojoDescriptor mojoDescriptor, 228 XMLWriter w, 229 DescriptorType type, 230 JavadocLinkGenerator javadocLinkGenerator, 231 boolean isV4) { 232 boolean containsXhtmlTextValues = mojoDescriptor instanceof ExtendedMojoDescriptor 233 && ((ExtendedMojoDescriptor) mojoDescriptor).containsXhtmlTextValues(); 234 235 w.startElement("mojo"); 236 237 // ---------------------------------------------------------------------- 238 // 239 // ---------------------------------------------------------------------- 240 241 w.startElement("goal"); 242 w.writeText(mojoDescriptor.getGoal()); 243 w.endElement(); 244 245 // ---------------------------------------------------------------------- 246 // 247 // ---------------------------------------------------------------------- 248 249 String description = mojoDescriptor.getDescription(); 250 251 if (description != null && !description.isEmpty()) { 252 w.startElement("description"); 253 w.writeText(getTextValue(type, containsXhtmlTextValues, mojoDescriptor.getDescription())); 254 w.endElement(); 255 } 256 257 // ---------------------------------------------------------------------- 258 // 259 // ---------------------------------------------------------------------- 260 261 if (StringUtils.isNotEmpty(mojoDescriptor.getDependencyResolutionRequired())) { 262 GeneratorUtils.element( 263 w, 264 isV4 ? "dependencyResolution" : "requiresDependencyResolution", 265 mojoDescriptor.getDependencyResolutionRequired()); 266 } 267 268 // ---------------------------------------------------------------------- 269 // 270 // ---------------------------------------------------------------------- 271 272 GeneratorUtils.element( 273 w, 274 isV4 ? "directInvocationOnly" : "requiresDirectInvocation", 275 String.valueOf(mojoDescriptor.isDirectInvocationOnly())); 276 277 // ---------------------------------------------------------------------- 278 // 279 // ---------------------------------------------------------------------- 280 281 GeneratorUtils.element( 282 w, isV4 ? "projectRequired" : "requiresProject", String.valueOf(mojoDescriptor.isProjectRequired())); 283 284 // ---------------------------------------------------------------------- 285 // 286 // ---------------------------------------------------------------------- 287 288 if (!isV4) { 289 GeneratorUtils.element(w, "requiresReports", String.valueOf(mojoDescriptor.isRequiresReports())); 290 } 291 292 // ---------------------------------------------------------------------- 293 // 294 // ---------------------------------------------------------------------- 295 296 GeneratorUtils.element(w, "aggregator", String.valueOf(mojoDescriptor.isAggregator())); 297 298 // ---------------------------------------------------------------------- 299 // 300 // ---------------------------------------------------------------------- 301 302 GeneratorUtils.element( 303 w, isV4 ? "onlineRequired" : "requiresOnline", String.valueOf(mojoDescriptor.isOnlineRequired())); 304 305 // ---------------------------------------------------------------------- 306 // 307 // ---------------------------------------------------------------------- 308 309 GeneratorUtils.element(w, "inheritedByDefault", String.valueOf(mojoDescriptor.isInheritedByDefault())); 310 311 // ---------------------------------------------------------------------- 312 // 313 // ---------------------------------------------------------------------- 314 315 if (StringUtils.isNotEmpty(mojoDescriptor.getPhase())) { 316 GeneratorUtils.element(w, "phase", mojoDescriptor.getPhase()); 317 } 318 319 // ---------------------------------------------------------------------- 320 // 321 // ---------------------------------------------------------------------- 322 323 if (StringUtils.isNotEmpty(mojoDescriptor.getExecutePhase())) { 324 GeneratorUtils.element(w, "executePhase", mojoDescriptor.getExecutePhase()); 325 } 326 327 if (StringUtils.isNotEmpty(mojoDescriptor.getExecuteGoal())) { 328 GeneratorUtils.element(w, "executeGoal", mojoDescriptor.getExecuteGoal()); 329 } 330 331 if (StringUtils.isNotEmpty(mojoDescriptor.getExecuteLifecycle())) { 332 GeneratorUtils.element(w, "executeLifecycle", mojoDescriptor.getExecuteLifecycle()); 333 } 334 335 // ---------------------------------------------------------------------- 336 // After links (v4 API only) 337 // ---------------------------------------------------------------------- 338 339 if (isV4 && mojoDescriptor instanceof ExtendedMojoDescriptor) { 340 List<ExtendedMojoDescriptor.AfterLink> afterLinks = 341 ((ExtendedMojoDescriptor) mojoDescriptor).getAfterLinks(); 342 if (!afterLinks.isEmpty()) { 343 w.startElement("afterLinks"); 344 for (ExtendedMojoDescriptor.AfterLink afterLink : afterLinks) { 345 w.startElement("afterLink"); 346 if (afterLink.getPhase() != null) { 347 GeneratorUtils.element(w, "phase", afterLink.getPhase()); 348 } 349 if (afterLink.getType() != null) { 350 GeneratorUtils.element(w, "type", afterLink.getType()); 351 } 352 if (afterLink.getScope() != null) { 353 GeneratorUtils.element(w, "scope", afterLink.getScope()); 354 } 355 w.endElement(); // afterLink 356 } 357 w.endElement(); // afterLinks 358 } 359 } 360 361 // ---------------------------------------------------------------------- 362 // 363 // ---------------------------------------------------------------------- 364 365 w.startElement("implementation"); 366 w.writeText(mojoDescriptor.getImplementation()); 367 w.endElement(); 368 369 // ---------------------------------------------------------------------- 370 // 371 // ---------------------------------------------------------------------- 372 373 w.startElement("language"); 374 w.writeText(mojoDescriptor.getLanguage()); 375 w.endElement(); 376 377 // ---------------------------------------------------------------------- 378 // 379 // ---------------------------------------------------------------------- 380 381 if (StringUtils.isNotEmpty(mojoDescriptor.getComponentConfigurator())) { 382 w.startElement("configurator"); 383 w.writeText(mojoDescriptor.getComponentConfigurator()); 384 w.endElement(); 385 } 386 387 // ---------------------------------------------------------------------- 388 // 389 // ---------------------------------------------------------------------- 390 391 if (!isV4 && StringUtils.isNotEmpty(mojoDescriptor.getComponentComposer())) { 392 w.startElement("composer"); 393 w.writeText(mojoDescriptor.getComponentComposer()); 394 w.endElement(); 395 } 396 397 // ---------------------------------------------------------------------- 398 // 399 // ---------------------------------------------------------------------- 400 401 if (!isV4) { 402 w.startElement("instantiationStrategy"); 403 w.writeText(mojoDescriptor.getInstantiationStrategy()); 404 w.endElement(); 405 } 406 407 // ---------------------------------------------------------------------- 408 // Strategy for handling repeated reference to mojo in 409 // the calculated (decorated, resolved) execution stack 410 // ---------------------------------------------------------------------- 411 412 if (!isV4) { 413 w.startElement("executionStrategy"); 414 w.writeText(mojoDescriptor.getExecutionStrategy()); 415 w.endElement(); 416 } 417 418 // ---------------------------------------------------------------------- 419 // 420 // ---------------------------------------------------------------------- 421 422 if (mojoDescriptor.getSince() != null) { 423 w.startElement("since"); 424 425 if (StringUtils.isEmpty(mojoDescriptor.getSince())) { 426 w.writeText("No version given"); 427 } else { 428 w.writeText(mojoDescriptor.getSince()); 429 } 430 431 w.endElement(); 432 } 433 434 // ---------------------------------------------------------------------- 435 // 436 // ---------------------------------------------------------------------- 437 438 if (mojoDescriptor.getDeprecated() != null) { 439 w.startElement("deprecated"); 440 441 if (StringUtils.isEmpty(mojoDescriptor.getDeprecated())) { 442 w.writeText("No reason given"); 443 } else { 444 w.writeText(getTextValue(type, containsXhtmlTextValues, mojoDescriptor.getDeprecated())); 445 } 446 447 w.endElement(); 448 } 449 450 // ---------------------------------------------------------------------- 451 // Extended (3.0) descriptor 452 // ---------------------------------------------------------------------- 453 454 if (mojoDescriptor instanceof ExtendedMojoDescriptor) { 455 ExtendedMojoDescriptor extendedMojoDescriptor = (ExtendedMojoDescriptor) mojoDescriptor; 456 if (extendedMojoDescriptor.getDependencyCollectionRequired() != null) { 457 GeneratorUtils.element( 458 w, 459 isV4 ? "dependencyCollection" : "requiresDependencyCollection", 460 extendedMojoDescriptor.getDependencyCollectionRequired()); 461 } 462 if (!isV4) { 463 GeneratorUtils.element(w, "threadSafe", String.valueOf(extendedMojoDescriptor.isThreadSafe())); 464 } 465 } 466 467 // ---------------------------------------------------------------------- 468 // Parameters 469 // ---------------------------------------------------------------------- 470 471 List<Parameter> parameters = mojoDescriptor.getParameters(); 472 473 w.startElement("parameters"); 474 475 Map<String, Requirement> requirements = new LinkedHashMap<>(); 476 477 Set<Parameter> configuration = new LinkedHashSet<>(); 478 479 if (parameters != null) { 480 if (type == DescriptorType.LIMITED_FOR_HELP_MOJO) { 481 PluginUtils.sortMojoParameters(parameters); 482 } 483 484 for (Parameter parameter : parameters) { 485 String expression = getExpression(parameter); 486 487 if ((expression != null && !expression.isEmpty()) && expression.startsWith("${component.")) { 488 // treat it as a component...a requirement, in other words. 489 490 // remove "component." plus expression delimiters 491 String role = expression.substring("${component.".length(), expression.length() - 1); 492 493 String roleHint = null; 494 495 int posRoleHintSeparator = role.indexOf('#'); 496 if (posRoleHintSeparator > 0) { 497 roleHint = role.substring(posRoleHintSeparator + 1); 498 499 role = role.substring(0, posRoleHintSeparator); 500 } 501 502 // TODO: remove deprecated expression 503 requirements.put(parameter.getName(), new Requirement(role, roleHint)); 504 } else if (parameter.getRequirement() != null) { 505 requirements.put(parameter.getName(), parameter.getRequirement()); 506 } 507 // don't show readonly parameters in help 508 else if (type != DescriptorType.LIMITED_FOR_HELP_MOJO || parameter.isEditable()) { 509 // treat it as a normal parameter. 510 511 w.startElement("parameter"); 512 513 GeneratorUtils.element(w, "name", parameter.getName()); 514 515 if (parameter.getAlias() != null) { 516 GeneratorUtils.element(w, "alias", parameter.getAlias()); 517 } 518 519 writeParameterType(w, type, javadocLinkGenerator, parameter, mojoDescriptor.getGoal()); 520 521 if (parameter.getSince() != null) { 522 w.startElement("since"); 523 524 if (StringUtils.isEmpty(parameter.getSince())) { 525 w.writeText("No version given"); 526 } else { 527 w.writeText(parameter.getSince()); 528 } 529 530 w.endElement(); 531 } 532 533 if (parameter.getDeprecated() != null) { 534 if (StringUtils.isEmpty(parameter.getDeprecated())) { 535 GeneratorUtils.element(w, "deprecated", "No reason given"); 536 } else { 537 GeneratorUtils.element( 538 w, 539 "deprecated", 540 getTextValue(type, containsXhtmlTextValues, parameter.getDeprecated())); 541 } 542 } 543 544 if (!isV4 && parameter.getImplementation() != null) { 545 GeneratorUtils.element(w, "implementation", parameter.getImplementation()); 546 } 547 548 GeneratorUtils.element(w, "required", Boolean.toString(parameter.isRequired())); 549 550 GeneratorUtils.element(w, "editable", Boolean.toString(parameter.isEditable())); 551 552 GeneratorUtils.element( 553 w, "description", getTextValue(type, containsXhtmlTextValues, parameter.getDescription())); 554 555 if (isV4) { 556 if (StringUtils.isNotEmpty(parameter.getExpression())) { 557 GeneratorUtils.element(w, "expression", parameter.getExpression()); 558 } 559 if (StringUtils.isNotEmpty(parameter.getDefaultValue())) { 560 GeneratorUtils.element(w, "defaultValue", parameter.getDefaultValue()); 561 } 562 } else { 563 if (StringUtils.isNotEmpty(parameter.getDefaultValue()) 564 || StringUtils.isNotEmpty(parameter.getExpression())) { 565 configuration.add(parameter); 566 } 567 } 568 569 w.endElement(); 570 } 571 } 572 } 573 574 w.endElement(); 575 576 // ---------------------------------------------------------------------- 577 // Configuration 578 // ---------------------------------------------------------------------- 579 580 if (!configuration.isEmpty()) { 581 w.startElement("configuration"); 582 583 for (Parameter parameter : configuration) { 584 if (type == DescriptorType.LIMITED_FOR_HELP_MOJO && !parameter.isEditable()) { 585 // don't show readonly parameters in help 586 continue; 587 } 588 589 w.startElement(parameter.getName()); 590 591 // strip type by parameter type (generics) information 592 String parameterType = StringUtils.chomp(parameter.getType(), "<"); 593 if (parameterType != null && !parameterType.isEmpty()) { 594 w.addAttribute("implementation", parameterType); 595 } 596 597 if (parameter.getDefaultValue() != null) { 598 w.addAttribute("default-value", parameter.getDefaultValue()); 599 } 600 601 if (StringUtils.isNotEmpty(parameter.getExpression())) { 602 w.writeText(parameter.getExpression()); 603 } 604 605 w.endElement(); 606 } 607 608 w.endElement(); 609 } 610 611 // ---------------------------------------------------------------------- 612 // Requirements 613 // ---------------------------------------------------------------------- 614 615 if (!requirements.isEmpty() && type != DescriptorType.LIMITED_FOR_HELP_MOJO) { 616 w.startElement("requirements"); 617 618 for (Map.Entry<String, Requirement> entry : requirements.entrySet()) { 619 String key = entry.getKey(); 620 Requirement requirement = entry.getValue(); 621 622 w.startElement("requirement"); 623 624 GeneratorUtils.element(w, "role", requirement.getRole()); 625 626 if (StringUtils.isNotEmpty(requirement.getRoleHint())) { 627 GeneratorUtils.element(w, "role-hint", requirement.getRoleHint()); 628 } 629 630 GeneratorUtils.element(w, "field-name", key); 631 632 w.endElement(); 633 } 634 635 w.endElement(); 636 } 637 638 w.endElement(); 639 } 640 641 /** 642 * Writes parameter type information and potentially also the related javadoc URL. 643 * 644 * @param w 645 * @param type 646 * @param javadocLinkGenerator 647 * @param parameter 648 * @param goal 649 */ 650 protected void writeParameterType( 651 XMLWriter w, 652 DescriptorType type, 653 JavadocLinkGenerator javadocLinkGenerator, 654 Parameter parameter, 655 String goal) { 656 String parameterType = parameter.getType(); 657 658 if (type == DescriptorType.STANDARD) { 659 // strip type by parameter type (generics) information for standard plugin descriptor 660 parameterType = StringUtils.chomp(parameterType, "<"); 661 } 662 GeneratorUtils.element(w, "type", parameterType); 663 664 if (type == DescriptorType.XHTML && javadocLinkGenerator != null) { 665 // skip primitives which never has javadoc 666 if (parameter.getType().indexOf('.') == -1) { 667 LOG.debug("Javadoc URLs are not available for primitive types like {}", parameter.getType()); 668 } else { 669 try { 670 URI javadocUrl = getJavadocUrlForType(javadocLinkGenerator, parameterType); 671 GeneratorUtils.element(w, "typeJavadocUrl", javadocUrl.toString()); 672 } catch (IllegalArgumentException e) { 673 LOG.warn( 674 "Could not get javadoc URL for type {} of parameter {} from goal {}: {}", 675 parameter.getType(), 676 parameter.getName(), 677 goal, 678 e.getMessage()); 679 } 680 } 681 } 682 } 683 684 private static String extractBinaryNameForJavadoc(String type) { 685 final String binaryName; 686 int startOfParameterType = type.indexOf("<"); 687 if (startOfParameterType != -1) { 688 // parse parameter type 689 String mainType = type.substring(0, startOfParameterType); 690 691 // some heuristics here 692 String[] parameterTypes = type.substring(startOfParameterType + 1, type.lastIndexOf(">")) 693 .split(",\\s*"); 694 switch (parameterTypes.length) { 695 case 1: // if only one parameter type, assume collection, first parameter type is most interesting 696 binaryName = extractBinaryNameForJavadoc(parameterTypes[0]); 697 break; 698 case 2: // if two parameter types assume map, second parameter type is most interesting 699 binaryName = extractBinaryNameForJavadoc(parameterTypes[1]); 700 break; 701 default: 702 // all other cases link to main type 703 binaryName = mainType; 704 } 705 } else { 706 binaryName = type; 707 } 708 return binaryName; 709 } 710 711 static URI getJavadocUrlForType(JavadocLinkGenerator javadocLinkGenerator, String type) { 712 return javadocLinkGenerator.createLink(extractBinaryNameForJavadoc(type)); 713 } 714 715 /** 716 * Get the expression value, eventually surrounding it with <code>${ }</code>. 717 * 718 * @param parameter the parameter 719 * @return the expression value 720 */ 721 private String getExpression(Parameter parameter) { 722 String expression = parameter.getExpression(); 723 if (StringUtils.isNotBlank(expression) && !expression.contains("${")) { 724 expression = "${" + expression.trim() + "}"; 725 parameter.setExpression(expression); 726 } 727 return expression; 728 } 729}