MPLUGIN-73: PluginXdocGenerator fails to decode javadoc inline tags

Submitted by: Benjamin Bentmann
Reviewed by: Vincent Siveton

o applied

git-svn-id: https://svn.apache.org/repos/asf/maven/plugin-tools/trunk@628491 13f79535-47bb-0310-9956-ffa450edef68
master
Vincent Siveton 2008-02-17 15:03:46 +00:00
parent 1b9e7ba6f4
commit cc94792fbd
2 changed files with 170 additions and 2 deletions

View File

@ -25,6 +25,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.Parameter;
@ -489,7 +491,7 @@ public class PluginXdocGenerator
tidy.setMakeClean( true );
tidy.setQuiet( true );
tidy.setShowWarnings( false );
tidy.parse( new StringInputStream( description ), out );
tidy.parse( new StringInputStream( decodeJavadocTags( description ) ), out );
// strip the header/body stuff
String LS = System.getProperty( "line.separator" );
@ -503,4 +505,116 @@ public class PluginXdocGenerator
return commentCleaned.substring( startPos, endPos );
}
/**
* Decodes javadoc inline tags into equivalent HTML tags. For instance, the inline tag "{@code <A&B>}" should be
* rendered as "<code>&lt;A&amp;B&gt;</code>".
*
* @param description The javadoc description to decode, may be <code>null</code>.
* @return The decoded description, never <code>null</code>.
*/
protected static String decodeJavadocTags( String description )
{
if ( StringUtils.isEmpty( description ) )
{
return "";
}
StringBuffer decoded = new StringBuffer( description.length() + 1024 );
Matcher matcher = Pattern.compile( "\\{@(\\w+)\\s*([^\\}]*)\\}" ).matcher( description );
while ( matcher.find() )
{
String tag = matcher.group( 1 );
String text = matcher.group( 2 );
text = StringUtils.replace( text, "&", "&amp;" );
text = StringUtils.replace( text, "<", "&lt;" );
text = StringUtils.replace( text, ">", "&gt;" );
if ( "code".equals( tag ) )
{
text = "<code>" + text + "</code>";
}
else if ( "link".equals( tag ) || "linkplain".equals( tag ) || "value".equals( tag ) )
{
String pattern = "(([^#\\.\\s]+\\.)*([^#\\.\\s]+))?" + "(#([^\\(\\s]*)(\\([^\\)]*\\))?\\s*(\\S.*)?)?";
final int LABEL = 7;
final int CLASS = 3;
final int MEMBER = 5;
final int ARGS = 6;
Matcher link = Pattern.compile( pattern ).matcher( text );
if ( link.matches() )
{
text = link.group( LABEL );
if ( StringUtils.isEmpty( text ) )
{
text = link.group( CLASS );
if ( StringUtils.isEmpty( text ) )
{
text = "";
}
if ( StringUtils.isNotEmpty( link.group( MEMBER ) ) )
{
if ( StringUtils.isNotEmpty( text ) )
{
text += '.';
}
text += link.group( MEMBER );
if ( StringUtils.isNotEmpty( link.group( ARGS ) ) )
{
text += "()";
}
}
}
}
if ( !"linkplain".equals( tag ) )
{
text = "<code>" + text + "</code>";
}
}
matcher.appendReplacement( decoded, ( text != null ) ? quoteReplacement( text ) : "" );
}
matcher.appendTail( decoded );
return decoded.toString();
}
/**
* Returns a literal replacement <code>String</code> for the specified <code>String</code>. This method
* produces a <code>String</code> that will work as a literal replacement <code>s</code> in the
* <code>appendReplacement</code> method of the {@link Matcher} class. The <code>String</code> produced will
* match the sequence of characters in <code>s</code> treated as a literal sequence. Slashes ('\') and dollar
* signs ('$') will be given no special meaning.
*
* TODO: copied from Matcher class of Java 1.5, remove once target platform can be upgraded
* @see <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Matcher.html">
* http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Matcher.html</a>
*
* @param s The string to be literalized
* @return A literal string replacement
*/
private static String quoteReplacement( String s )
{
if ( ( s.indexOf( '\\' ) == -1 ) && ( s.indexOf( '$' ) == -1 ) )
return s;
StringBuffer sb = new StringBuffer();
for ( int i = 0; i < s.length(); i++ )
{
char c = s.charAt( i );
if ( c == '\\' )
{
sb.append( '\\' );
sb.append( '\\' );
}
else if ( c == '$' )
{
sb.append( '\\' );
sb.append( '$' );
}
else
{
sb.append( c );
}
}
return sb.toString();
}
}

View File

@ -41,4 +41,58 @@ public class PluginXdocGeneratorTest
assertEquals( "Generates <i>something</i> <b> for the project.</b>", PluginXdocGenerator
.makeHtmlValid( javadoc ) );
}
}
public void testDecodeJavadocTags()
{
String javadoc = null;
assertEquals( "", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "";
assertEquals( "", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@code text}";
assertEquals( "<code>text</code>", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@code <A&B>}";
assertEquals( "<code>&lt;A&amp;B&gt;</code>", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@literal text}";
assertEquals( "text", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@literal text} {@literal text}";
assertEquals( "text text", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@literal <A&B>}";
assertEquals( "&lt;A&amp;B&gt;", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@link Class}";
assertEquals( "<code>Class</code>", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@linkplain Class}";
assertEquals( "Class", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@linkplain #field}";
assertEquals( "field", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@linkplain Class#field}";
assertEquals( "Class.field", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@linkplain #method()}";
assertEquals( "method()", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@linkplain #method(Object arg)}";
assertEquals( "method()", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@linkplain #method(Object, String)}";
assertEquals( "method()", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@linkplain #method(Object, String) label}";
assertEquals( "label", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@linkplain Class#method(Object, String)}";
assertEquals( "Class.method()", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
javadoc = "{@linkplain Class#method(Object, String) label}";
assertEquals( "label", PluginXdocGenerator.decodeJavadocTags( javadoc ) );
}
}