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