1 package org.apache.maven.plugin.javadoc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.StringReader;
27 import java.io.StringWriter;
28 import java.io.Writer;
29 import java.lang.reflect.Method;
30 import java.net.MalformedURLException;
31 import java.net.URL;
32 import java.net.URLClassLoader;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.Iterator;
37 import java.util.LinkedHashMap;
38 import java.util.LinkedList;
39 import java.util.List;
40 import java.util.Locale;
41 import java.util.Map;
42 import java.util.Properties;
43 import java.util.StringTokenizer;
44 import java.util.regex.Pattern;
45
46 import org.apache.commons.lang.ClassUtils;
47 import org.apache.maven.artifact.Artifact;
48 import org.apache.maven.artifact.DependencyResolutionRequiredException;
49 import org.apache.maven.artifact.repository.ArtifactRepository;
50 import org.apache.maven.plugin.AbstractMojo;
51 import org.apache.maven.plugin.MojoExecutionException;
52 import org.apache.maven.plugin.MojoFailureException;
53 import org.apache.maven.project.MavenProject;
54 import org.apache.maven.settings.Settings;
55 import org.apache.maven.shared.invoker.MavenInvocationException;
56 import org.codehaus.plexus.components.interactivity.InputHandler;
57 import org.codehaus.plexus.util.FileUtils;
58 import org.codehaus.plexus.util.IOUtil;
59 import org.codehaus.plexus.util.ReaderFactory;
60 import org.codehaus.plexus.util.StringUtils;
61 import org.codehaus.plexus.util.WriterFactory;
62
63 import com.thoughtworks.qdox.JavaDocBuilder;
64 import com.thoughtworks.qdox.model.AbstractInheritableJavaEntity;
65 import com.thoughtworks.qdox.model.AbstractJavaEntity;
66 import com.thoughtworks.qdox.model.Annotation;
67 import com.thoughtworks.qdox.model.DocletTag;
68 import com.thoughtworks.qdox.model.JavaClass;
69 import com.thoughtworks.qdox.model.JavaField;
70 import com.thoughtworks.qdox.model.JavaMethod;
71 import com.thoughtworks.qdox.model.JavaParameter;
72 import com.thoughtworks.qdox.model.Type;
73 import com.thoughtworks.qdox.model.TypeVariable;
74 import com.thoughtworks.qdox.parser.ParseException;
75
76
77
78
79
80
81
82
83
84
85 public abstract class AbstractFixJavadocMojo
86 extends AbstractMojo
87 {
88
89 private static final String EOL = System.getProperty( "line.separator" );
90
91
92 private static final String AUTHOR_TAG = "author";
93
94
95 private static final String VERSION_TAG = "version";
96
97
98 private static final String SINCE_TAG = "since";
99
100
101 private static final String PARAM_TAG = "param";
102
103
104 private static final String RETURN_TAG = "return";
105
106
107 private static final String THROWS_TAG = "throws";
108
109
110 private static final String INHERITED_TAG = "{@inheritDoc}";
111
112
113 private static final String START_JAVADOC = "/**";
114
115
116 private static final String END_JAVADOC = "*/";
117
118
119 private static final String SEPARATOR_JAVADOC = " * ";
120
121
122 private static final String INHERITED_JAVADOC = START_JAVADOC + " " + INHERITED_TAG + " " + END_JAVADOC;
123
124
125 private static final String FIX_TAGS_ALL = "all";
126
127
128 private static final String LEVEL_PUBLIC = "public";
129
130
131 private static final String LEVEL_PROTECTED = "protected";
132
133
134 private static final String LEVEL_PACKAGE = "package";
135
136
137 private static final String LEVEL_PRIVATE = "private";
138
139
140 private static final String CLIRR_MAVEN_PLUGIN_GROUPID = "org.codehaus.mojo";
141
142
143 private static final String CLIRR_MAVEN_PLUGIN_ARTIFACTID = "clirr-maven-plugin";
144
145
146 private static final String CLIRR_MAVEN_PLUGIN_VERSION = "2.2.2";
147
148
149 private static final String CLIRR_MAVEN_PLUGIN_GOAL = "check";
150
151
152
153
154
155
156
157
158
159
160 private InputHandler inputHandler;
161
162
163
164
165
166
167
168
169
170
171
172
173
174 private String comparisonVersion;
175
176
177
178
179
180
181
182
183 private String defaultAuthor;
184
185
186
187
188
189
190
191 private String defaultSince;
192
193
194
195
196
197
198
199
200
201
202 private String defaultVersion = "\u0024Id: \u0024";
203
204
205
206
207
208
209
210 private String encoding;
211
212
213
214
215
216
217 private String excludes;
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234 private String fixTags;
235
236
237
238
239
240
241 private boolean fixClassComment;
242
243
244
245
246
247
248 private boolean fixFieldComment;
249
250
251
252
253
254
255 private boolean fixMethodComment;
256
257
258
259
260
261
262 private boolean force;
263
264
265
266
267
268
269 protected boolean ignoreClirr;
270
271
272
273
274
275
276 private String includes;
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295 private String level;
296
297
298
299
300
301
302 private ArtifactRepository localRepository;
303
304
305
306
307
308
309 private File outputDirectory;
310
311
312
313
314
315
316
317
318 private MavenProject project;
319
320
321
322
323
324
325
326
327 private Settings settings;
328
329
330
331
332
333
334 private ClassLoader projectClassLoader;
335
336
337
338
339
340 private String[] fixTagsSplitted;
341
342
343 private List clirrNewClasses;
344
345
346 private Map clirrNewMethods;
347
348
349 private List sinceClasses;
350
351
352 public void execute()
353 throws MojoExecutionException, MojoFailureException
354 {
355 if ( !fixClassComment && !fixFieldComment && !fixMethodComment )
356 {
357 getLog().info( "Specified to NOT fix classes, fields and methods. Nothing to do." );
358 return;
359 }
360
361
362 init();
363
364 if ( fixTagsSplitted.length == 0 )
365 {
366 getLog().info( "No fix tag specified. Nothing to do." );
367 return;
368 }
369
370
371 if ( !preCheck() )
372 {
373 return;
374 }
375
376
377 try
378 {
379 executeClirr();
380 }
381 catch ( MavenInvocationException e )
382 {
383 if ( getLog().isDebugEnabled() )
384 {
385 getLog().error( "MavenInvocationException: " + e.getMessage(), e );
386 }
387 else
388 {
389 getLog().error( "MavenInvocationException: " + e.getMessage() );
390 }
391 getLog().info( "Clirr is ignored." );
392 }
393
394
395 try
396 {
397 JavaClass[] javaClasses = getQdoxClasses();
398
399 if ( javaClasses != null )
400 {
401 for ( int i = 0; i < javaClasses.length; i++ )
402 {
403 JavaClass javaClass = javaClasses[i];
404
405 processFix( javaClass );
406 }
407 }
408 }
409 catch ( IOException e )
410 {
411 throw new MojoExecutionException( "IOException: " + e.getMessage(), e );
412 }
413 }
414
415
416
417
418
419
420
421
422
423 protected String getArtifactType( MavenProject p )
424 {
425 return p.getArtifact().getType();
426 }
427
428
429
430
431
432 protected List getProjectSourceRoots( MavenProject p )
433 {
434 return ( p.getCompileSourceRoots() == null ? Collections.EMPTY_LIST
435 : new LinkedList( p.getCompileSourceRoots() ) );
436 }
437
438
439
440
441
442
443 protected List getCompileClasspathElements( MavenProject p )
444 throws DependencyResolutionRequiredException
445 {
446 return ( p.getCompileClasspathElements() == null ? Collections.EMPTY_LIST
447 : new LinkedList( p.getCompileClasspathElements() ) );
448 }
449
450
451
452
453
454 protected static String getJavaMethodAsString( JavaMethod javaMethod )
455 {
456 StringBuffer sb = new StringBuffer();
457
458 sb.append( javaMethod.getParentClass().getFullyQualifiedName() );
459 sb.append( "#" ).append( javaMethod.getCallSignature() );
460
461 return sb.toString();
462 }
463
464
465
466
467
468
469
470
471 private void init()
472 {
473
474 if ( StringUtils.isEmpty( defaultAuthor ) )
475 {
476 defaultAuthor = System.getProperty( "user.name" );
477 }
478
479
480 int i = defaultSince.indexOf( "-" + Artifact.SNAPSHOT_VERSION );
481 if ( i != -1 )
482 {
483 defaultSince = defaultSince.substring( 0, i );
484 }
485
486
487 if ( !FIX_TAGS_ALL.equalsIgnoreCase( fixTags.trim() ) )
488 {
489 String[] split = StringUtils.split( fixTags, "," );
490 List filtered = new LinkedList();
491 for ( int j = 0; j < split.length; j++ )
492 {
493 String s = split[j].trim();
494 if ( FIX_TAGS_ALL.equalsIgnoreCase( s.trim() ) || AUTHOR_TAG.equalsIgnoreCase( s.trim() )
495 || VERSION_TAG.equalsIgnoreCase( s.trim() ) || SINCE_TAG.equalsIgnoreCase( s.trim() )
496 || PARAM_TAG.equalsIgnoreCase( s.trim() ) || RETURN_TAG.equalsIgnoreCase( s.trim() )
497 || THROWS_TAG.equalsIgnoreCase( s.trim() ) )
498 {
499 filtered.add( s );
500 }
501 else
502 {
503 if ( getLog().isWarnEnabled() )
504 {
505 getLog().warn( "Unrecognized '" + s + "' for fixTags parameter. Ignored it!" );
506 }
507 }
508 }
509 fixTags = StringUtils.join( filtered.iterator(), "," );
510 }
511 fixTagsSplitted = StringUtils.split( fixTags, "," );
512
513
514 if ( StringUtils.isEmpty( encoding ) )
515 {
516 if ( getLog().isWarnEnabled() )
517 {
518 getLog().warn(
519 "File encoding has not been set, using platform encoding "
520 + ReaderFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
521 }
522 encoding = ReaderFactory.FILE_ENCODING;
523 }
524
525
526 if ( !( LEVEL_PUBLIC.equalsIgnoreCase( level.trim() ) || LEVEL_PROTECTED.equalsIgnoreCase( level.trim() )
527 || LEVEL_PACKAGE.equalsIgnoreCase( level.trim() ) || LEVEL_PRIVATE.equalsIgnoreCase( level.trim() ) ) )
528 {
529 if ( getLog().isWarnEnabled() )
530 {
531 getLog().warn( "Unrecognized '" + level + "' for level parameter, using 'protected' level." );
532 }
533 level = "protected";
534 }
535 }
536
537
538
539
540
541 private boolean preCheck()
542 throws MojoExecutionException
543 {
544 if ( force )
545 {
546 return true;
547 }
548
549 if ( outputDirectory != null
550 && !outputDirectory.getAbsolutePath().equals( getProjectSourceDirectory().getAbsolutePath() ) )
551 {
552 return true;
553 }
554
555 if ( !settings.isInteractiveMode() )
556 {
557 getLog().error(
558 "Maven is not attempt to interact with the user for input. "
559 + "Verify the <interactiveMode/> configuration in your settings." );
560 return false;
561 }
562
563 getLog().warn( "" );
564 getLog().warn( " WARRANTY DISCLAIMER" );
565 getLog().warn( "" );
566 getLog().warn( "All warranties with regard to this Maven goal are disclaimed!" );
567 getLog().warn( "The changes will be done directly in the source code." );
568 getLog().warn(
569 "The Maven Team strongly recommends the use of a SCM software BEFORE executing this "
570 + "goal." );
571 getLog().warn( "" );
572
573 while ( true )
574 {
575 getLog().info( "Are you sure to proceed? [Y]es [N]o" );
576
577 try
578 {
579 String userExpression = inputHandler.readLine();
580 if ( userExpression == null || userExpression.toLowerCase( Locale.ENGLISH ).equalsIgnoreCase( "Y" )
581 || userExpression.toLowerCase( Locale.ENGLISH ).equalsIgnoreCase( "Yes" ) )
582 {
583 getLog().info( "OK, let's proceed..." );
584 break;
585 }
586 if ( userExpression == null || userExpression.toLowerCase( Locale.ENGLISH ).equalsIgnoreCase( "N" )
587 || userExpression.toLowerCase( Locale.ENGLISH ).equalsIgnoreCase( "No" ) )
588 {
589 getLog().info( "No changes in your sources occur." );
590 return false;
591 }
592 }
593 catch ( IOException e )
594 {
595 throw new MojoExecutionException( "Unable to read from standard input.", e );
596 }
597 }
598
599 return true;
600 }
601
602
603
604
605 private File getProjectSourceDirectory()
606 {
607 return new File( project.getBuild().getSourceDirectory() );
608 }
609
610
611
612
613
614
615 private void executeClirr()
616 throws MavenInvocationException
617 {
618 if ( ignoreClirr )
619 {
620 getLog().info( "Clirr is ignored." );
621 return;
622 }
623
624 String clirrGoal = getFullClirrGoal();
625
626
627 File clirrTextOutputFile =
628 FileUtils.createTempFile( "clirr", ".txt", new File( project.getBuild().getDirectory() ) );
629 Properties properties = new Properties();
630 properties.put( "textOutputFile", clirrTextOutputFile.getAbsolutePath() );
631 properties.put( "comparisonVersion", comparisonVersion );
632 properties.put( "failOnError", "false" );
633
634 File invokerDir = new File( project.getBuild().getDirectory(), "invoker" );
635 invokerDir.mkdirs();
636 File invokerLogFile = FileUtils.createTempFile( "clirr-maven-plugin", ".txt", invokerDir );
637 new File( project.getBuild().getDirectory(), "invoker-clirr-maven-plugin.txt" );
638 JavadocUtil.invokeMaven( getLog(), new File( localRepository.getBasedir() ), project.getFile(),
639 Collections.singletonList( clirrGoal ), properties, invokerLogFile );
640
641 try
642 {
643 if ( invokerLogFile.exists() )
644 {
645 String invokerLogContent = StringUtils.unifyLineSeparators( FileUtils.fileRead( invokerLogFile, "UTF-8" ) );
646
647 final String artifactNotFoundMsg =
648 "Unable to find a previous version of the project in the repository";
649 if ( invokerLogContent.indexOf( artifactNotFoundMsg ) != -1 )
650 {
651 getLog().warn( "No previous artifact has been deployed, Clirr is ignored." );
652 return;
653 }
654 }
655 }
656 catch ( IOException e )
657 {
658 getLog().debug( "IOException: " + e.getMessage() );
659 }
660
661 try
662 {
663 parseClirrTextOutputFile( clirrTextOutputFile );
664 }
665 catch ( IOException e )
666 {
667 if ( getLog().isDebugEnabled() )
668 {
669 getLog().debug( "IOException: " + e.getMessage(), e );
670 }
671 getLog().info(
672 "IOException when parsing Clirr output '" + clirrTextOutputFile.getAbsolutePath()
673 + "', Clirr is ignored." );
674 }
675 }
676
677
678
679
680
681 private void parseClirrTextOutputFile( File clirrTextOutputFile )
682 throws IOException
683 {
684 if ( !clirrTextOutputFile.exists() )
685 {
686 if ( getLog().isInfoEnabled() )
687 {
688 getLog().info(
689 "No Clirr output file '" + clirrTextOutputFile.getAbsolutePath()
690 + "' exists, Clirr is ignored." );
691 }
692 return;
693 }
694
695 if ( getLog().isInfoEnabled() )
696 {
697 getLog().info( "Clirr output file was created: " + clirrTextOutputFile.getAbsolutePath() );
698 }
699
700 clirrNewClasses = new LinkedList();
701 clirrNewMethods = new LinkedHashMap();
702
703 BufferedReader input = new BufferedReader( ReaderFactory.newReader( clirrTextOutputFile, "UTF-8" ) );
704 String line = null;
705 while ( ( line = input.readLine() ) != null )
706 {
707 String[] split = StringUtils.split( line, ":" );
708 if ( split.length != 4 )
709 {
710 if ( getLog().isDebugEnabled() )
711 {
712 getLog().debug( "Unable to parse the clirr line: " + line );
713 }
714 continue;
715 }
716
717 int code;
718 try
719 {
720 code = Integer.parseInt( split[1].trim() );
721 }
722 catch ( NumberFormatException e )
723 {
724 if ( getLog().isDebugEnabled() )
725 {
726 getLog().debug( "Unable to parse the clirr line: " + line );
727 }
728 continue;
729 }
730
731
732
733
734
735 List list;
736 String[] splits2;
737 switch ( code )
738 {
739 case 7011:
740 list = (List) clirrNewMethods.get( split[2].trim() );
741 if ( list == null )
742 {
743 list = new ArrayList();
744 }
745 splits2 = StringUtils.split( split[3].trim(), "'" );
746 if ( splits2.length != 3 )
747 {
748 continue;
749 }
750 list.add( splits2[1].trim() );
751 clirrNewMethods.put( split[2].trim(), list );
752 break;
753
754 case 7012:
755 list = (List) clirrNewMethods.get( split[2].trim() );
756 if ( list == null )
757 {
758 list = new ArrayList();
759 }
760 splits2 = StringUtils.split( split[3].trim(), "'" );
761 if ( splits2.length != 3 )
762 {
763 continue;
764 }
765 list.add( splits2[1].trim() );
766 clirrNewMethods.put( split[2].trim(), list );
767 break;
768
769 case 8000:
770 clirrNewClasses.add( split[2].trim() );
771 break;
772 default:
773 break;
774 }
775 }
776
777 if ( clirrNewClasses.isEmpty() && clirrNewMethods.isEmpty() )
778 {
779 getLog().info( "Clirr NOT found API differences." );
780 }
781 else
782 {
783 getLog().info( "Clirr found API differences, i.e. new classes/interfaces or methods." );
784 }
785 }
786
787
788
789
790
791 private boolean fixTag( String tag )
792 {
793 if ( fixTagsSplitted.length == 1 && fixTagsSplitted[0].equals( FIX_TAGS_ALL ) )
794 {
795 return true;
796 }
797
798 for ( int i = 0; i < fixTagsSplitted.length; i++ )
799 {
800 if ( fixTagsSplitted[i].trim().equals( tag ) )
801 {
802 return true;
803 }
804 }
805
806 return false;
807 }
808
809
810
811
812
813
814
815
816
817 private JavaClass[] getQdoxClasses()
818 throws IOException, MojoExecutionException
819 {
820 if ( "pom".equals( project.getPackaging().toLowerCase() ) )
821 {
822 getLog().warn( "This project has 'pom' packaging, no Java sources is available." );
823 return null;
824 }
825
826 List javaFiles = new LinkedList();
827 for ( Iterator i = getProjectSourceRoots( project ).iterator(); i.hasNext(); )
828 {
829 File f = new File( (String) i.next() );
830 if ( f.isDirectory() )
831 {
832 javaFiles.addAll( FileUtils.getFiles( f, includes, excludes, true ) );
833 }
834 else
835 {
836 if ( getLog().isWarnEnabled() )
837 {
838 getLog().warn( f + " doesn't exist. Ignored it." );
839 }
840 }
841 }
842
843 JavaDocBuilder builder = new JavaDocBuilder();
844 builder.getClassLibrary().addClassLoader( getProjectClassLoader() );
845 builder.setEncoding( encoding );
846 for ( Iterator i = javaFiles.iterator(); i.hasNext(); )
847 {
848 File f = (File) i.next();
849 if ( !f.getAbsolutePath().toLowerCase( Locale.ENGLISH ).endsWith( ".java" )
850 && getLog().isWarnEnabled() )
851 {
852 getLog().warn( "'" + f + "' is not a Java file. Ignored it." );
853 continue;
854 }
855
856 try
857 {
858 builder.addSource( f );
859 }
860 catch ( ParseException e )
861 {
862 if ( getLog().isWarnEnabled() )
863 {
864 getLog().warn( "QDOX ParseException: " + e.getMessage() + ". Can't fix it." );
865 }
866 }
867 }
868
869 return builder.getClasses();
870 }
871
872
873
874
875
876 private ClassLoader getProjectClassLoader()
877 throws MojoExecutionException
878 {
879 if ( projectClassLoader == null )
880 {
881 List classPath;
882 try
883 {
884 classPath = getCompileClasspathElements( project );
885 }
886 catch ( DependencyResolutionRequiredException e )
887 {
888 throw new MojoExecutionException( "DependencyResolutionRequiredException: " + e.getMessage(), e );
889 }
890
891 List urls = new ArrayList( classPath.size() );
892 Iterator iter = classPath.iterator();
893 while ( iter.hasNext() )
894 {
895 try
896 {
897 urls.add( new File( ( (String) iter.next() ) ).toURL() );
898 }
899 catch ( MalformedURLException e )
900 {
901 throw new MojoExecutionException( "MalformedURLException: " + e.getMessage(), e );
902 }
903 }
904
905 projectClassLoader = new URLClassLoader( (URL[]) urls.toArray( new URL[urls.size()] ), null );
906 }
907
908 return projectClassLoader;
909 }
910
911
912
913
914
915
916
917
918 private void processFix( JavaClass javaClass )
919 throws IOException, MojoExecutionException
920 {
921
922 if ( javaClass.isInner() )
923 {
924 return;
925 }
926
927 File javaFile = new File( javaClass.getSource().getURL().getFile() );
928
929 final String originalContent = StringUtils.unifyLineSeparators( FileUtils.fileRead( javaFile, encoding ) );
930
931 if ( getLog().isDebugEnabled() )
932 {
933 getLog().debug( "Fixing " + javaClass.getFullyQualifiedName() );
934 }
935
936 final StringWriter stringWriter = new StringWriter();
937 BufferedReader reader = null;
938 try
939 {
940 reader = new BufferedReader( new StringReader( originalContent ) );
941
942 String line;
943 int lineNumber = 0;
944 while ( ( line = reader.readLine() ) != null )
945 {
946 lineNumber++;
947 final String indent = autodetectIndentation( line );
948
949
950 if ( javaClass.getComment() == null && javaClass.getAnnotations() != null
951 && javaClass.getAnnotations().length != 0 )
952 {
953 if ( lineNumber == javaClass.getAnnotations()[0].getLineNumber() )
954 {
955 fixClassComment( stringWriter, originalContent, javaClass, indent );
956
957 takeCareSingleComment( stringWriter, originalContent, javaClass );
958 }
959 }
960 else
961 {
962 if ( lineNumber == javaClass.getLineNumber() )
963 {
964 fixClassComment( stringWriter, originalContent, javaClass, indent );
965
966 takeCareSingleComment( stringWriter, originalContent, javaClass );
967 }
968 }
969
970
971 if ( javaClass.getFields() != null )
972 {
973 for ( int i = 0; i < javaClass.getFields().length; i++ )
974 {
975 JavaField field = javaClass.getFields()[i];
976
977 if ( lineNumber == field.getLineNumber() )
978 {
979 fixFieldComment( stringWriter, javaClass, field, indent );
980 }
981 }
982 }
983
984
985 if ( javaClass.getMethods() != null )
986 {
987 for ( int i = 0; i < javaClass.getMethods().length; i++ )
988 {
989 JavaMethod method = javaClass.getMethods()[i];
990
991 if ( lineNumber == method.getLineNumber() )
992 {
993 fixMethodComment( stringWriter, originalContent, method, indent );
994
995 takeCareSingleComment( stringWriter, originalContent, method );
996 }
997 }
998 }
999
1000 stringWriter.write( line );
1001 stringWriter.write( EOL );
1002 }
1003 }
1004 finally
1005 {
1006 IOUtil.close( reader );
1007 }
1008
1009 if ( getLog().isDebugEnabled() )
1010 {
1011 getLog().debug( "Saving " + javaClass.getFullyQualifiedName() );
1012 }
1013
1014 if ( outputDirectory != null
1015 && !outputDirectory.getAbsolutePath().equals( getProjectSourceDirectory().getAbsolutePath() ) )
1016 {
1017 String path =
1018 StringUtils.replace( javaFile.getAbsolutePath().replaceAll( "\\\\", "/" ),
1019 project.getBuild().getSourceDirectory().replaceAll( "\\\\", "/" ), "" );
1020 javaFile = new File( outputDirectory, path );
1021 javaFile.getParentFile().mkdirs();
1022 }
1023 writeFile( javaFile, encoding, stringWriter.toString() );
1024 }
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056 private void takeCareSingleComment( final StringWriter stringWriter, final String originalContent,
1057 final AbstractInheritableJavaEntity entity )
1058 throws IOException
1059 {
1060 if ( entity.getComment() == null )
1061 {
1062 return;
1063 }
1064
1065 String javadocComment = trimRight( extractOriginalJavadoc( originalContent, entity ) );
1066 String extraComment =
1067 javadocComment.substring( javadocComment.indexOf( END_JAVADOC ) + END_JAVADOC.length() );
1068 if ( StringUtils.isNotEmpty( extraComment ) )
1069 {
1070 if ( extraComment.indexOf( EOL ) != -1 )
1071 {
1072 stringWriter.write( extraComment.substring( extraComment.indexOf( EOL ) + EOL.length() ) );
1073 }
1074 else
1075 {
1076 stringWriter.write( extraComment );
1077 }
1078 stringWriter.write( EOL );
1079 }
1080 }
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092 private void fixClassComment( final StringWriter stringWriter, final String originalContent,
1093 final JavaClass javaClass, final String indent )
1094 throws MojoExecutionException, IOException
1095 {
1096 if ( !fixClassComment )
1097 {
1098 return;
1099 }
1100
1101 if ( !isInLevel( javaClass.getModifiers() ) )
1102 {
1103 return;
1104 }
1105
1106
1107 if ( javaClass.getComment() == null )
1108 {
1109 addDefaultClassComment( stringWriter, javaClass, indent );
1110 return;
1111 }
1112
1113
1114 updateEntityComment( stringWriter, originalContent, javaClass, indent );
1115 }
1116
1117
1118
1119
1120
1121 private boolean isInLevel( String[] modifiers )
1122 {
1123 List modifiersAsList = Arrays.asList( modifiers );
1124
1125 if ( LEVEL_PUBLIC.equalsIgnoreCase( level.trim() ) )
1126 {
1127 if ( modifiersAsList.contains( LEVEL_PUBLIC ) )
1128 {
1129 return true;
1130 }
1131
1132 return false;
1133 }
1134
1135 if ( LEVEL_PROTECTED.equalsIgnoreCase( level.trim() ) )
1136 {
1137 if ( modifiersAsList.contains( LEVEL_PUBLIC ) || modifiersAsList.contains( LEVEL_PROTECTED ) )
1138 {
1139 return true;
1140 }
1141
1142 return false;
1143 }
1144
1145 if ( LEVEL_PACKAGE.equalsIgnoreCase( level.trim() ) )
1146 {
1147 if ( !modifiersAsList.contains( LEVEL_PRIVATE ) )
1148 {
1149 return true;
1150 }
1151
1152 return false;
1153 }
1154
1155
1156 return true;
1157 }
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193 private void addDefaultClassComment( final StringWriter stringWriter, final JavaClass javaClass,
1194 final String indent )
1195 {
1196 StringBuffer sb = new StringBuffer();
1197
1198 sb.append( indent ).append( START_JAVADOC );
1199 sb.append( EOL );
1200 sb.append( indent ).append( SEPARATOR_JAVADOC );
1201 sb.append( getDefaultClassJavadocComment( javaClass ) );
1202 sb.append( EOL );
1203
1204 appendSeparator( sb, indent );
1205
1206 appendDefaultAuthorTag( sb, indent );
1207
1208 appendDefaultVersionTag( sb, indent );
1209
1210 if ( fixTag( SINCE_TAG ) )
1211 {
1212 if ( !ignoreClirr )
1213 {
1214 if ( isNewClassFromLastVersion( javaClass ) )
1215 {
1216 appendDefaultSinceTag( sb, indent );
1217 }
1218 }
1219 else
1220 {
1221 appendDefaultSinceTag( sb, indent );
1222 addSinceClasses( javaClass );
1223 }
1224 }
1225
1226 sb.append( indent ).append( " " ).append( END_JAVADOC );
1227 sb.append( EOL );
1228
1229 stringWriter.write( sb.toString() );
1230 }
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241 private void fixFieldComment( final StringWriter stringWriter, final JavaClass javaClass,
1242 final JavaField field, final String indent )
1243 throws IOException
1244 {
1245 if ( !fixFieldComment )
1246 {
1247 return;
1248 }
1249
1250 if ( !javaClass.isInterface() )
1251 {
1252 if ( !isInLevel( field.getModifiers() ) )
1253 {
1254 return;
1255 }
1256
1257 if ( !field.isStatic() )
1258 {
1259 return;
1260 }
1261 }
1262
1263
1264 if ( field.getComment() == null )
1265 {
1266 addDefaultFieldComment( stringWriter, field, indent );
1267 return;
1268 }
1269
1270
1271 }
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292 private void addDefaultFieldComment( final StringWriter stringWriter, final JavaField field,
1293 final String indent )
1294 throws IOException
1295 {
1296 StringBuffer sb = new StringBuffer();
1297
1298 sb.append( indent ).append( START_JAVADOC ).append( " " );
1299 sb.append( "Constant <code>" ).append( field.getName() );
1300
1301 if ( StringUtils.isNotEmpty( field.getInitializationExpression() ) )
1302 {
1303 String qualifiedName = field.getType().getJavaClass().getFullyQualifiedName();
1304
1305 if ( qualifiedName.equals( Byte.TYPE.toString() ) || qualifiedName.equals( Short.TYPE.toString() )
1306 || qualifiedName.equals( Integer.TYPE.toString() ) || qualifiedName.equals( Long.TYPE.toString() )
1307 || qualifiedName.equals( Float.TYPE.toString() ) || qualifiedName.equals( Double.TYPE.toString() )
1308 || qualifiedName.equals( Boolean.TYPE.toString() )
1309 || qualifiedName.equals( Character.TYPE.toString() ) )
1310 {
1311 sb.append( "=" );
1312 sb.append( field.getInitializationExpression().trim() );
1313 }
1314
1315 if ( qualifiedName.equals( String.class.getName() ) )
1316 {
1317 StringBuffer value = new StringBuffer();
1318 String[] lines = getLines( field.getInitializationExpression() );
1319 for ( int i = 0; i < lines.length; i++ )
1320 {
1321 String line = lines[i];
1322
1323 StringTokenizer token = new StringTokenizer( line.trim(), "\"\n\r" );
1324 while ( token.hasMoreTokens() )
1325 {
1326 String s = token.nextToken();
1327
1328 if ( s.trim().equals( "+" ) )
1329 {
1330 continue;
1331 }
1332 if ( s.trim().endsWith( "\\" ) )
1333 {
1334 s += "\"";
1335 }
1336 value.append( s );
1337 }
1338 }
1339
1340 sb.append( "=\"" );
1341
1342 if ( value.length() < 40 )
1343 {
1344 sb.append( value.toString() ).append( "\"" );
1345 }
1346 else
1347 {
1348 sb.append( value.toString().substring( 0, 39 ) ).append( "\"{trunked}" );
1349 }
1350 }
1351 }
1352
1353 sb.append( "</code> " ).append( END_JAVADOC );
1354 sb.append( EOL );
1355
1356 stringWriter.write( sb.toString() );
1357 }
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369 private void fixMethodComment( final StringWriter stringWriter, final String originalContent,
1370 final JavaMethod javaMethod, final String indent )
1371 throws MojoExecutionException, IOException
1372 {
1373 if ( !fixMethodComment )
1374 {
1375 return;
1376 }
1377
1378 if ( !javaMethod.getParentClass().isInterface() && !isInLevel( javaMethod.getModifiers() ) )
1379 {
1380 return;
1381 }
1382
1383
1384 if ( javaMethod.getComment() == null )
1385 {
1386 addDefaultMethodComment( stringWriter, javaMethod, indent );
1387 return;
1388 }
1389
1390
1391 updateEntityComment( stringWriter, originalContent, javaMethod, indent );
1392 }
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432 private void addDefaultMethodComment( final StringWriter stringWriter, final JavaMethod javaMethod,
1433 final String indent )
1434 throws MojoExecutionException
1435 {
1436 StringBuffer sb = new StringBuffer();
1437
1438
1439 if ( isInherited( javaMethod ) )
1440 {
1441 sb.append( indent ).append( INHERITED_JAVADOC );
1442 sb.append( EOL );
1443
1444 stringWriter.write( sb.toString() );
1445 return;
1446 }
1447
1448 sb.append( indent ).append( START_JAVADOC );
1449 sb.append( EOL );
1450 sb.append( indent ).append( SEPARATOR_JAVADOC );
1451 sb.append( getDefaultMethodJavadocComment( javaMethod ) );
1452 sb.append( EOL );
1453
1454 boolean separatorAdded = false;
1455 if ( fixTag( PARAM_TAG ) )
1456 {
1457 if ( javaMethod.getParameters() != null )
1458 {
1459 for ( int i = 0; i < javaMethod.getParameters().length; i++ )
1460 {
1461 JavaParameter javaParameter = javaMethod.getParameters()[i];
1462
1463 separatorAdded = appendDefaultParamTag( sb, indent, separatorAdded, javaParameter );
1464 }
1465 }
1466
1467 if ( javaMethod.getTypeParameters() != null )
1468 {
1469 for ( int i = 0; i < javaMethod.getTypeParameters().length; i++ )
1470 {
1471 TypeVariable typeParam = javaMethod.getTypeParameters()[i];
1472
1473 separatorAdded = appendDefaultParamTag( sb, indent, separatorAdded, typeParam );
1474 }
1475 }
1476 }
1477 if ( fixTag( RETURN_TAG ) && javaMethod.getReturns() != null && !javaMethod.getReturns().isVoid() )
1478 {
1479 separatorAdded = appendDefaultReturnTag( sb, indent, separatorAdded, javaMethod );
1480 }
1481 if ( fixTag( THROWS_TAG ) && javaMethod.getExceptions() != null && javaMethod.getExceptions().length > 0 )
1482 {
1483 for ( int i = 0; i < javaMethod.getExceptions().length; i++ )
1484 {
1485 Type exception = javaMethod.getExceptions()[i];
1486
1487 separatorAdded = appendDefaultThrowsTag( sb, indent, separatorAdded, exception );
1488 }
1489 }
1490 if ( fixTag( SINCE_TAG ) && isNewMethodFromLastRevision( javaMethod ) )
1491 {
1492 separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
1493 }
1494
1495 sb.append( indent ).append( " " ).append( END_JAVADOC );
1496 sb.append( EOL );
1497
1498 stringWriter.write( sb.toString() );
1499 }
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509 private void updateEntityComment( final StringWriter stringWriter, final String originalContent,
1510 final AbstractInheritableJavaEntity entity, final String indent )
1511 throws MojoExecutionException, IOException
1512 {
1513 String s = stringWriter.toString();
1514 int i = s.lastIndexOf( START_JAVADOC );
1515 if ( i != -1 )
1516 {
1517 String tmp = s.substring( 0, i );
1518 if ( tmp.lastIndexOf( EOL ) != -1 )
1519 {
1520 tmp = tmp.substring( 0, tmp.lastIndexOf( EOL ) );
1521 }
1522 stringWriter.getBuffer().delete( 0, stringWriter.getBuffer().length() );
1523 stringWriter.write( tmp );
1524 stringWriter.write( EOL );
1525 }
1526
1527 updateJavadocComment( stringWriter, originalContent, entity, indent );
1528 }
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538 private void updateJavadocComment( final StringWriter stringWriter, final String originalContent,
1539 final AbstractInheritableJavaEntity entity, final String indent )
1540 throws MojoExecutionException, IOException
1541 {
1542 if ( entity.getComment() == null && ( entity.getTags() == null || entity.getTags().length == 0 ) )
1543 {
1544 return;
1545 }
1546
1547 boolean isJavaMethod = false;
1548 if ( entity instanceof JavaMethod )
1549 {
1550 isJavaMethod = true;
1551 }
1552
1553 StringBuffer sb = new StringBuffer();
1554
1555
1556 if ( isJavaMethod )
1557 {
1558 JavaMethod javaMethod = (JavaMethod) entity;
1559
1560 if ( isInherited( javaMethod ) )
1561 {
1562
1563 if ( StringUtils.isEmpty( javaMethod.getComment() ) )
1564 {
1565 sb.append( indent ).append( INHERITED_JAVADOC );
1566 sb.append( EOL );
1567 stringWriter.write( sb.toString() );
1568 return;
1569 }
1570
1571 String javadoc = getJavadocComment( originalContent, javaMethod );
1572
1573 or no tags
1574 if ( hasInheritedTag( javadoc )
1575 && ( javaMethod.getTags() == null || javaMethod.getTags().length == 0 ) )
1576 {
1577 sb.append( indent ).append( INHERITED_JAVADOC );
1578 sb.append( EOL );
1579 stringWriter.write( sb.toString() );
1580 return;
1581 }
1582
1583 if ( javadoc.indexOf( START_JAVADOC ) != -1 )
1584 {
1585 javadoc = javadoc.substring( javadoc.indexOf( START_JAVADOC ) + START_JAVADOC.length() );
1586 }
1587 if ( javadoc.indexOf( END_JAVADOC ) != -1 )
1588 {
1589 javadoc = javadoc.substring( 0, javadoc.indexOf( END_JAVADOC ) );
1590 }
1591
1592 sb.append( indent ).append( START_JAVADOC );
1593 sb.append( EOL );
1594 if ( javadoc.indexOf( INHERITED_TAG ) == -1 )
1595 {
1596 sb.append( indent ).append( SEPARATOR_JAVADOC ).append( INHERITED_TAG );
1597 sb.append( EOL );
1598 appendSeparator( sb, indent );
1599 }
1600 javadoc = removeLastEmptyJavadocLines( javadoc );
1601 javadoc = alignIndentationJavadocLines( javadoc, indent );
1602 sb.append( javadoc );
1603 sb.append( EOL );
1604 if ( javaMethod.getTags() != null )
1605 {
1606 for ( int i = 0; i < javaMethod.getTags().length; i++ )
1607 {
1608 DocletTag docletTag = javaMethod.getTags()[i];
1609
1610
1611 if ( docletTag.getName().equals( PARAM_TAG )
1612 || docletTag.getName().equals( RETURN_TAG )
1613 || docletTag.getName().equals( THROWS_TAG ) )
1614 {
1615 continue;
1616 }
1617
1618 String s = getJavadocComment( originalContent, entity, docletTag );
1619 s = removeLastEmptyJavadocLines( s );
1620 s = alignIndentationJavadocLines( s, indent );
1621 sb.append( s );
1622 sb.append( EOL );
1623 }
1624 }
1625 sb.append( indent ).append( " " ).append( END_JAVADOC );
1626 sb.append( EOL );
1627
1628 if ( hasInheritedTag( sb.toString().trim() ) )
1629 {
1630 sb = new StringBuffer();
1631 sb.append( indent ).append( INHERITED_JAVADOC );
1632 sb.append( EOL );
1633 stringWriter.write( sb.toString() );
1634 return;
1635 }
1636
1637 stringWriter.write( sb.toString() );
1638 return;
1639 }
1640 }
1641
1642 sb.append( indent ).append( START_JAVADOC );
1643 sb.append( EOL );
1644
1645
1646 if ( StringUtils.isNotEmpty( entity.getComment() ) )
1647 {
1648 updateJavadocComment( sb, originalContent, entity, indent );
1649 }
1650 else
1651 {
1652 addDefaultJavadocComment( sb, entity, indent, isJavaMethod );
1653 }
1654
1655
1656 if ( entity.getTags() != null && entity.getTags().length > 0 )
1657 {
1658 updateJavadocTags( sb, originalContent, entity, indent, isJavaMethod );
1659 }
1660 else
1661 {
1662 addDefaultJavadocTags( sb, entity, indent, isJavaMethod );
1663 }
1664
1665 sb = new StringBuffer( removeLastEmptyJavadocLines( sb.toString() ) ).append( EOL );
1666
1667 sb.append( indent ).append( " " ).append( END_JAVADOC );
1668 sb.append( EOL );
1669
1670 stringWriter.write( sb.toString() );
1671 }
1672
1673
1674
1675
1676
1677
1678
1679
1680 private void updateJavadocComment( final StringBuffer sb, final String originalContent,
1681 final AbstractInheritableJavaEntity entity, final String indent )
1682 throws IOException
1683 {
1684 String comment = getJavadocComment( originalContent, entity );
1685 comment = removeLastEmptyJavadocLines( comment );
1686 comment = alignIndentationJavadocLines( comment, indent );
1687
1688 if ( comment.indexOf( START_JAVADOC ) != -1 )
1689 {
1690 comment = comment.substring( comment.indexOf( START_JAVADOC ) + START_JAVADOC.length() );
1691 comment = indent + SEPARATOR_JAVADOC + comment.trim();
1692 }
1693 if ( comment.indexOf( END_JAVADOC ) != -1 )
1694 {
1695 comment = comment.substring( 0, comment.indexOf( END_JAVADOC ) );
1696 }
1697
1698 String[] lines = getLines( comment );
1699 for ( int i = 0; i < lines.length; i++ )
1700 {
1701 sb.append( indent ).append( " " ).append( lines[i].trim() );
1702 sb.append( EOL );
1703 }
1704 }
1705
1706
1707
1708
1709
1710
1711
1712 private void addDefaultJavadocComment( final StringBuffer sb, final AbstractInheritableJavaEntity entity,
1713 final String indent, final boolean isJavaMethod )
1714 {
1715 sb.append( indent ).append( SEPARATOR_JAVADOC );
1716 if ( isJavaMethod )
1717 {
1718 sb.append( getDefaultMethodJavadocComment( (JavaMethod) entity ) );
1719 }
1720 else
1721 {
1722 sb.append( getDefaultClassJavadocComment( (JavaClass) entity ) );
1723 }
1724 sb.append( EOL );
1725 }
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736 private void updateJavadocTags( final StringBuffer sb, final String originalContent,
1737 final AbstractInheritableJavaEntity entity, final String indent,
1738 final boolean isJavaMethod )
1739 throws IOException, MojoExecutionException
1740 {
1741 appendSeparator( sb, indent );
1742
1743
1744 JavaEntityTags javaEntityTags = parseJavadocTags( originalContent, entity, indent, isJavaMethod );
1745
1746
1747 updateJavadocTags( sb, entity, isJavaMethod, javaEntityTags );
1748
1749
1750 addMissingJavadocTags( sb, entity, indent, isJavaMethod, javaEntityTags );
1751 }
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763 private JavaEntityTags parseJavadocTags( final String originalContent,
1764 final AbstractInheritableJavaEntity entity, final String indent,
1765 final boolean isJavaMethod )
1766 throws IOException
1767 {
1768 JavaEntityTags javaEntityTags = new JavaEntityTags( entity, isJavaMethod );
1769 for ( int i = 0; i < entity.getTags().length; i++ )
1770 {
1771 DocletTag docletTag = entity.getTags()[i];
1772
1773 String originalJavadocTag = getJavadocComment( originalContent, entity, docletTag );
1774 originalJavadocTag = removeLastEmptyJavadocLines( originalJavadocTag );
1775 originalJavadocTag = alignIndentationJavadocLines( originalJavadocTag, indent );
1776
1777 javaEntityTags.getNamesTags().add( docletTag.getName() );
1778
1779 if ( isJavaMethod )
1780 {
1781 String[] params = docletTag.getParameters();
1782 if ( params.length < 1 )
1783 {
1784 continue;
1785 }
1786
1787 params = fixQdox173( params );
1788 String paramName = params[0];
1789 if ( docletTag.getName().equals( PARAM_TAG ) )
1790 {
1791 javaEntityTags.putJavadocParamTag( paramName, originalJavadocTag );
1792 }
1793 else if ( docletTag.getName().equals( RETURN_TAG ) )
1794 {
1795 javaEntityTags.setJavadocReturnTag( originalJavadocTag );
1796 }
1797 else if ( docletTag.getName().equals( THROWS_TAG ) )
1798 {
1799 javaEntityTags.putJavadocThrowsTag( paramName, originalJavadocTag );
1800 }
1801 else
1802 {
1803 javaEntityTags.getUnknownTags().add( originalJavadocTag );
1804 }
1805 }
1806 else
1807 {
1808 javaEntityTags.getUnknownTags().add( originalJavadocTag );
1809 }
1810 }
1811
1812 return javaEntityTags;
1813 }
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823 private void updateJavadocTags( final StringBuffer sb, final AbstractInheritableJavaEntity entity,
1824 final boolean isJavaMethod, final JavaEntityTags javaEntityTags )
1825 {
1826 for ( int i = 0; i < entity.getTags().length; i++ )
1827 {
1828 DocletTag docletTag = entity.getTags()[i];
1829
1830 if ( isJavaMethod )
1831 {
1832 JavaMethod javaMethod = (JavaMethod) entity;
1833
1834 String[] params = docletTag.getParameters();
1835 if ( params.length < 1 )
1836 {
1837 continue;
1838 }
1839
1840 if ( docletTag.getName().equals( PARAM_TAG ) )
1841 {
1842 writeParamTag( sb, javaMethod, javaEntityTags, params );
1843 }
1844 else if ( docletTag.getName().equals( RETURN_TAG ) )
1845 {
1846 writeReturnTag( sb, javaMethod, javaEntityTags );
1847 }
1848 else if ( docletTag.getName().equals( THROWS_TAG ) )
1849 {
1850 writeThrowsTag( sb, javaMethod, javaEntityTags, params );
1851 }
1852 else
1853 {
1854
1855 for ( Iterator it = javaEntityTags.getUnknownTags().iterator(); it.hasNext(); )
1856 {
1857 String originalJavadocTag = it.next().toString();
1858
1859 if ( StringUtils.removeDuplicateWhitespace( originalJavadocTag ).trim()
1860 .indexOf( "@" + docletTag.getName() ) != -1 )
1861 {
1862 it.remove();
1863 sb.append( originalJavadocTag );
1864 sb.append( EOL );
1865 }
1866 }
1867 }
1868 }
1869 else
1870 {
1871 for ( Iterator it = javaEntityTags.getUnknownTags().iterator(); it.hasNext(); )
1872 {
1873 String originalJavadocTag = it.next().toString();
1874
1875 if ( StringUtils.removeDuplicateWhitespace( originalJavadocTag ).trim()
1876 .indexOf( "@" + docletTag.getName() ) != -1 )
1877 {
1878 it.remove();
1879 sb.append( originalJavadocTag );
1880 sb.append( EOL );
1881 }
1882 }
1883 }
1884
1885 if ( sb.toString().endsWith( EOL ) )
1886 {
1887 sb.delete( sb.toString().lastIndexOf( EOL ), sb.toString().length() );
1888 }
1889
1890 sb.append( EOL );
1891 }
1892 }
1893
1894 private void writeParamTag( final StringBuffer sb, final JavaMethod javaMethod,
1895 final JavaEntityTags javaEntityTags, String[] params )
1896 {
1897 params = fixQdox173( params );
1898
1899 String paramName = params[0];
1900
1901 if ( !fixTag( PARAM_TAG ) )
1902 {
1903
1904 String originalJavadocTag = javaEntityTags.getJavadocParamTag( paramName );
1905 if ( originalJavadocTag != null )
1906 {
1907 sb.append( originalJavadocTag );
1908 }
1909 return;
1910 }
1911
1912 boolean found = false;
1913 JavaParameter javaParam = javaMethod.getParameterByName( paramName );
1914 if ( javaParam == null )
1915 {
1916
1917 TypeVariable[] typeParams = javaMethod.getTypeParameters();
1918 for ( int i = 0; i < typeParams.length; i++ )
1919 {
1920 if ( typeParams[i].getGenericValue().equals( paramName ) )
1921 {
1922 found = true;
1923 }
1924 }
1925 }
1926 else
1927 {
1928 found = true;
1929 }
1930
1931 if ( !found )
1932 {
1933 if ( getLog().isWarnEnabled() )
1934 {
1935 StringBuffer warn = new StringBuffer();
1936
1937 warn.append( "Fixed unknown param '" ).append( paramName ).append( "' defined in " );
1938 warn.append( getJavaMethodAsString( javaMethod ) );
1939
1940 getLog().warn( warn.toString() );
1941 }
1942
1943 if ( sb.toString().endsWith( EOL ) )
1944 {
1945 sb.delete( sb.toString().lastIndexOf( EOL ), sb.toString().length() );
1946 }
1947 }
1948 else
1949 {
1950 String originalJavadocTag = javaEntityTags.getJavadocParamTag( paramName );
1951 if ( originalJavadocTag != null )
1952 {
1953 sb.append( originalJavadocTag );
1954 String s = "@" + PARAM_TAG + " " + paramName;
1955 if ( StringUtils.removeDuplicateWhitespace( originalJavadocTag ).trim().endsWith( s ) )
1956 {
1957 sb.append( " " );
1958 sb.append( getDefaultJavadocForType( javaParam.getType() ) );
1959 }
1960 }
1961 }
1962 }
1963
1964 private void writeReturnTag( final StringBuffer sb, final JavaMethod javaMethod,
1965 final JavaEntityTags javaEntityTags )
1966 {
1967 String originalJavadocTag = javaEntityTags.getJavadocReturnTag();
1968 if ( originalJavadocTag == null )
1969 {
1970 return;
1971 }
1972
1973 if ( !fixTag( RETURN_TAG ) )
1974 {
1975
1976 sb.append( originalJavadocTag );
1977 return;
1978 }
1979
1980 if ( StringUtils.isNotEmpty( originalJavadocTag ) && javaMethod.getReturns() != null
1981 && !javaMethod.getReturns().isVoid() )
1982 {
1983 sb.append( originalJavadocTag );
1984 if ( originalJavadocTag.trim().endsWith( "@" + RETURN_TAG ) )
1985 {
1986 sb.append( " " );
1987 sb.append( getDefaultJavadocForType( javaMethod.getReturns() ) );
1988 }
1989 }
1990 }
1991
1992 private void writeThrowsTag( final StringBuffer sb, final JavaMethod javaMethod,
1993 final JavaEntityTags javaEntityTags, final String[] params )
1994 {
1995 String exceptionClassName = params[0];
1996
1997 String originalJavadocTag = javaEntityTags.getJavadocThrowsTag( exceptionClassName );
1998 if ( originalJavadocTag == null )
1999 {
2000 return;
2001 }
2002
2003 if ( !fixTag( THROWS_TAG ) )
2004 {
2005
2006 sb.append( originalJavadocTag );
2007 return;
2008 }
2009
2010 if ( javaMethod.getExceptions() != null )
2011 {
2012 for ( int j = 0; j < javaMethod.getExceptions().length; j++ )
2013 {
2014 Type exception = javaMethod.getExceptions()[j];
2015
2016 if ( exception.getValue().endsWith( exceptionClassName ) )
2017 {
2018 originalJavadocTag =
2019 StringUtils.replace( originalJavadocTag, exceptionClassName, exception.getValue() );
2020 if ( StringUtils.removeDuplicateWhitespace( originalJavadocTag ).trim()
2021 .endsWith( "@" + THROWS_TAG + " " + exception.getValue() ) )
2022 {
2023 originalJavadocTag += " if any.";
2024 }
2025
2026 sb.append( originalJavadocTag );
2027
2028
2029 javaEntityTags.putJavadocThrowsTag( exception.getValue(), originalJavadocTag );
2030
2031 return;
2032 }
2033 }
2034 }
2035
2036
2037 Class clazz = getRuntimeExceptionClass( javaMethod.getParentClass(), exceptionClassName );
2038 if ( clazz != null )
2039 {
2040 sb.append( StringUtils.replace( originalJavadocTag, exceptionClassName, clazz.getName() ) );
2041
2042
2043 javaEntityTags.putJavadocThrowsTag( clazz.getName(), originalJavadocTag );
2044
2045 return;
2046 }
2047
2048 if ( getLog().isWarnEnabled() )
2049 {
2050 StringBuffer warn = new StringBuffer();
2051
2052 warn.append( "Unknown throws exception '" ).append( exceptionClassName ).append( "' defined in " );
2053 warn.append( getJavaMethodAsString( javaMethod ) );
2054
2055 getLog().warn( warn.toString() );
2056 }
2057
2058 sb.append( originalJavadocTag );
2059 if ( params.length == 1 )
2060 {
2061 sb.append( " if any." );
2062 }
2063 }
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075 private void addMissingJavadocTags( final StringBuffer sb, final AbstractInheritableJavaEntity entity,
2076 final String indent, final boolean isJavaMethod,
2077 final JavaEntityTags javaEntityTags )
2078 throws MojoExecutionException
2079 {
2080 if ( isJavaMethod )
2081 {
2082 JavaMethod javaMethod = (JavaMethod) entity;
2083
2084 if ( fixTag( PARAM_TAG ) )
2085 {
2086 if ( javaMethod.getParameters() != null )
2087 {
2088 for ( int i = 0; i < javaMethod.getParameters().length; i++ )
2089 {
2090 JavaParameter javaParameter = javaMethod.getParameters()[i];
2091
2092 if ( javaEntityTags.getJavadocParamTag( javaParameter.getName(), true ) == null )
2093 {
2094 appendDefaultParamTag( sb, indent, javaParameter );
2095 }
2096 }
2097 }
2098
2099 if ( javaMethod.getTypeParameters() != null )
2100 {
2101 for ( int i = 0; i < javaMethod.getTypeParameters().length; i++ )
2102 {
2103 TypeVariable typeParam = javaMethod.getTypeParameters()[i];
2104
2105 if ( javaEntityTags.getJavadocParamTag( "<" + typeParam.getName() + ">", true ) == null )
2106 {
2107 appendDefaultParamTag( sb, indent, typeParam );
2108 }
2109 }
2110 }
2111 }
2112
2113 if ( fixTag( RETURN_TAG ) && StringUtils.isEmpty( javaEntityTags.getJavadocReturnTag() )
2114 && javaMethod.getReturns() != null && !javaMethod.getReturns().isVoid() )
2115 {
2116 appendDefaultReturnTag( sb, indent, javaMethod );
2117 }
2118
2119 if ( fixTag( THROWS_TAG ) && javaMethod.getExceptions() != null )
2120 {
2121 for ( int i = 0; i < javaMethod.getExceptions().length; i++ )
2122 {
2123 Type exception = javaMethod.getExceptions()[i];
2124
2125 if ( javaEntityTags.getJavadocThrowsTag( exception.getValue(), true ) == null )
2126 {
2127 appendDefaultThrowsTag( sb, indent, exception );
2128 }
2129 }
2130 }
2131 }
2132 else
2133 {
2134 if ( !javaEntityTags.getNamesTags().contains( AUTHOR_TAG ) )
2135 {
2136 appendDefaultAuthorTag( sb, indent );
2137 }
2138 if ( !javaEntityTags.getNamesTags().contains( VERSION_TAG ) )
2139 {
2140 appendDefaultVersionTag( sb, indent );
2141 }
2142 }
2143 if ( fixTag( SINCE_TAG ) && !javaEntityTags.getNamesTags().contains( SINCE_TAG ) )
2144 {
2145 if ( !isJavaMethod )
2146 {
2147 if ( !ignoreClirr )
2148 {
2149 if ( isNewClassFromLastVersion( (JavaClass) entity ) )
2150 {
2151 appendDefaultSinceTag( sb, indent );
2152 }
2153 }
2154 else
2155 {
2156 appendDefaultSinceTag( sb, indent );
2157 addSinceClasses( (JavaClass) entity );
2158 }
2159 }
2160 else
2161 {
2162 if ( !ignoreClirr )
2163 {
2164 if ( isNewMethodFromLastRevision( (JavaMethod) entity ) )
2165 {
2166 appendDefaultSinceTag( sb, indent );
2167 }
2168 }
2169 else
2170 {
2171 if ( sinceClasses != null && !sinceClassesContains( ( (JavaMethod) entity ).getParentClass() ) )
2172 {
2173 appendDefaultSinceTag( sb, indent );
2174 }
2175 }
2176 }
2177 }
2178 }
2179
2180
2181
2182
2183
2184
2185
2186
2187 private void addDefaultJavadocTags( final StringBuffer sb, final AbstractInheritableJavaEntity entity,
2188 final String indent, final boolean isJavaMethod )
2189 throws MojoExecutionException
2190 {
2191 boolean separatorAdded = false;
2192 if ( isJavaMethod )
2193 {
2194 JavaMethod javaMethod = (JavaMethod) entity;
2195
2196 if ( fixTag( PARAM_TAG ) && javaMethod.getParameters() != null )
2197 {
2198 for ( int i = 0; i < javaMethod.getParameters().length; i++ )
2199 {
2200 JavaParameter javaParameter = javaMethod.getParameters()[i];
2201
2202 separatorAdded = appendDefaultParamTag( sb, indent, separatorAdded, javaParameter );
2203 }
2204 }
2205
2206 if ( fixTag( RETURN_TAG ) )
2207 {
2208 if ( javaMethod.getReturns() != null && !javaMethod.getReturns().isVoid() )
2209 {
2210 separatorAdded = appendDefaultReturnTag( sb, indent, separatorAdded, javaMethod );
2211 }
2212 }
2213
2214 if ( fixTag( THROWS_TAG ) && javaMethod.getExceptions() != null )
2215 {
2216 for ( int i = 0; i < javaMethod.getExceptions().length; i++ )
2217 {
2218 Type exception = javaMethod.getExceptions()[i];
2219
2220 separatorAdded = appendDefaultThrowsTag( sb, indent, separatorAdded, exception );
2221 }
2222 }
2223 }
2224 else
2225 {
2226 separatorAdded = appendDefaultAuthorTag( sb, indent, separatorAdded );
2227
2228 separatorAdded = appendDefaultVersionTag( sb, indent, separatorAdded );
2229 }
2230
2231 if ( fixTag( SINCE_TAG ) )
2232 {
2233 if ( !isJavaMethod )
2234 {
2235 JavaClass javaClass = (JavaClass) entity;
2236
2237 if ( !ignoreClirr )
2238 {
2239 if ( isNewClassFromLastVersion( javaClass ) )
2240 {
2241 separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
2242 }
2243 }
2244 else
2245 {
2246 separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
2247
2248 addSinceClasses( javaClass );
2249 }
2250 }
2251 else
2252 {
2253 JavaMethod javaMethod = (JavaMethod) entity;
2254
2255 if ( !ignoreClirr )
2256 {
2257 if ( isNewMethodFromLastRevision( javaMethod ) )
2258 {
2259 separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
2260 }
2261 }
2262 else
2263 {
2264 if ( sinceClasses != null && !sinceClassesContains( javaMethod.getParentClass() ) )
2265 {
2266 separatorAdded = appendDefaultSinceTag( sb, indent, separatorAdded );
2267 }
2268 }
2269 }
2270 }
2271 }
2272
2273
2274
2275
2276
2277
2278
2279 private boolean appendDefaultAuthorTag( final StringBuffer sb, final String indent, boolean separatorAdded )
2280 {
2281 if ( !fixTag( AUTHOR_TAG ) )
2282 {
2283 return separatorAdded;
2284 }
2285
2286 if ( !separatorAdded )
2287 {
2288 appendSeparator( sb, indent );
2289 separatorAdded = true;
2290 }
2291
2292 appendDefaultAuthorTag( sb, indent );
2293 return separatorAdded;
2294 }
2295
2296
2297
2298
2299
2300 private void appendDefaultAuthorTag( final StringBuffer sb, final String indent )
2301 {
2302 if ( !fixTag( AUTHOR_TAG ) )
2303 {
2304 return;
2305 }
2306
2307 sb.append( indent ).append( " * @" ).append( AUTHOR_TAG ).append( " " );
2308 sb.append( defaultAuthor );
2309 sb.append( EOL );
2310 }
2311
2312
2313
2314
2315
2316
2317
2318 private boolean appendDefaultSinceTag( final StringBuffer sb, final String indent, boolean separatorAdded )
2319 {
2320 if ( !fixTag( SINCE_TAG ) )
2321 {
2322 return separatorAdded;
2323 }
2324
2325 if ( !separatorAdded )
2326 {
2327 appendSeparator( sb, indent );
2328 separatorAdded = true;
2329 }
2330
2331 appendDefaultSinceTag( sb, indent );
2332 return separatorAdded;
2333 }
2334
2335
2336
2337
2338
2339 private void appendDefaultSinceTag( final StringBuffer sb, final String indent )
2340 {
2341 if ( !fixTag( SINCE_TAG ) )
2342 {
2343 return;
2344 }
2345
2346 sb.append( indent ).append( " * @" ).append( SINCE_TAG ).append( " " );
2347 sb.append( defaultSince );
2348 sb.append( EOL );
2349 }
2350
2351
2352
2353
2354
2355
2356
2357 private boolean appendDefaultVersionTag( final StringBuffer sb, final String indent, boolean separatorAdded )
2358 {
2359 if ( !fixTag( VERSION_TAG ) )
2360 {
2361 return separatorAdded;
2362 }
2363
2364 if ( !separatorAdded )
2365 {
2366 appendSeparator( sb, indent );
2367 separatorAdded = true;
2368 }
2369
2370 appendDefaultVersionTag( sb, indent );
2371 return separatorAdded;
2372 }
2373
2374
2375
2376
2377
2378 private void appendDefaultVersionTag( final StringBuffer sb, final String indent )
2379 {
2380 if ( !fixTag( VERSION_TAG ) )
2381 {
2382 return;
2383 }
2384
2385 sb.append( indent ).append( " * @" ).append( VERSION_TAG ).append( " " );
2386 sb.append( defaultVersion );
2387 sb.append( EOL );
2388 }
2389
2390
2391
2392
2393
2394
2395
2396
2397 private boolean appendDefaultParamTag( final StringBuffer sb, final String indent, boolean separatorAdded,
2398 final JavaParameter javaParameter )
2399 {
2400 if ( !fixTag( PARAM_TAG ) )
2401 {
2402 return separatorAdded;
2403 }
2404
2405 if ( !separatorAdded )
2406 {
2407 appendSeparator( sb, indent );
2408 separatorAdded = true;
2409 }
2410
2411 appendDefaultParamTag( sb, indent, javaParameter );
2412 return separatorAdded;
2413 }
2414
2415
2416
2417
2418
2419
2420
2421
2422 private boolean appendDefaultParamTag( final StringBuffer sb, final String indent, boolean separatorAdded,
2423 final TypeVariable typeParameter )
2424 {
2425 if ( !fixTag( PARAM_TAG ) )
2426 {
2427 return separatorAdded;
2428 }
2429
2430 if ( !separatorAdded )
2431 {
2432 appendSeparator( sb, indent );
2433 separatorAdded = true;
2434 }
2435
2436 appendDefaultParamTag( sb, indent, typeParameter );
2437 return separatorAdded;
2438 }
2439
2440
2441
2442
2443
2444
2445 private void appendDefaultParamTag( final StringBuffer sb, final String indent,
2446 final JavaParameter javaParameter )
2447 {
2448 if ( !fixTag( PARAM_TAG ) )
2449 {
2450 return;
2451 }
2452
2453 sb.append( indent ).append( " * @" ).append( PARAM_TAG ).append( " " );
2454 sb.append( javaParameter.getName() );
2455 sb.append( " " );
2456 sb.append( getDefaultJavadocForType( javaParameter.getType() ) );
2457 sb.append( EOL );
2458 }
2459
2460
2461
2462
2463
2464
2465 private void appendDefaultParamTag( final StringBuffer sb, final String indent,
2466 final TypeVariable typeParameter )
2467 {
2468 if ( !fixTag( PARAM_TAG ) )
2469 {
2470 return;
2471 }
2472
2473 sb.append( indent ).append( " * @" ).append( PARAM_TAG ).append( " " );
2474 sb.append( "<" + typeParameter.getName() + ">" );
2475 sb.append( " " );
2476 sb.append( getDefaultJavadocForType( typeParameter ) );
2477 sb.append( EOL );
2478 }
2479
2480
2481
2482
2483
2484
2485
2486
2487 private boolean appendDefaultReturnTag( final StringBuffer sb, final String indent, boolean separatorAdded,
2488 final JavaMethod javaMethod )
2489 {
2490 if ( !fixTag( RETURN_TAG ) )
2491 {
2492 return separatorAdded;
2493 }
2494
2495 if ( !separatorAdded )
2496 {
2497 appendSeparator( sb, indent );
2498 separatorAdded = true;
2499 }
2500
2501 appendDefaultReturnTag( sb, indent, javaMethod );
2502 return separatorAdded;
2503 }
2504
2505
2506
2507
2508
2509
2510 private void appendDefaultReturnTag( final StringBuffer sb, final String indent, final JavaMethod javaMethod )
2511 {
2512 if ( !fixTag( RETURN_TAG ) )
2513 {
2514 return;
2515 }
2516
2517 sb.append( indent ).append( " * @" ).append( RETURN_TAG ).append( " " );
2518 sb.append( getDefaultJavadocForType( javaMethod.getReturns() ) );
2519 sb.append( EOL );
2520 }
2521
2522
2523
2524
2525
2526
2527
2528
2529 private boolean appendDefaultThrowsTag( final StringBuffer sb, final String indent, boolean separatorAdded,
2530 final Type exception )
2531 {
2532 if ( !fixTag( THROWS_TAG ) )
2533 {
2534 return separatorAdded;
2535 }
2536
2537 if ( !separatorAdded )
2538 {
2539 appendSeparator( sb, indent );
2540 separatorAdded = true;
2541 }
2542
2543 appendDefaultThrowsTag( sb, indent, exception );
2544 return separatorAdded;
2545 }
2546
2547
2548
2549
2550
2551
2552 private void appendDefaultThrowsTag( final StringBuffer sb, final String indent, final Type exception )
2553 {
2554 if ( !fixTag( THROWS_TAG ) )
2555 {
2556 return;
2557 }
2558
2559 sb.append( indent ).append( " * @" ).append( THROWS_TAG ).append( " " );
2560 sb.append( exception.getJavaClass().getFullyQualifiedName() );
2561 sb.append( " if any." );
2562 sb.append( EOL );
2563 }
2564
2565
2566
2567
2568
2569 private void appendSeparator( final StringBuffer sb, final String indent )
2570 {
2571 sb.append( indent ).append( " *" );
2572 sb.append( EOL );
2573 }
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583 private boolean isInherited( JavaMethod javaMethod )
2584 throws MojoExecutionException, SecurityException
2585 {
2586 if ( javaMethod.getAnnotations() != null )
2587 {
2588 for ( int i = 0; i < javaMethod.getAnnotations().length; i++ )
2589 {
2590 Annotation annotation = javaMethod.getAnnotations()[i];
2591
2592 if ( annotation.toString().equals( "@java.lang.Override()" ) )
2593 {
2594 return true;
2595 }
2596 }
2597 }
2598
2599 Class clazz = getClass( javaMethod.getParentClass().getFullyQualifiedName() );
2600
2601 List interfaces = ClassUtils.getAllInterfaces( clazz );
2602 for ( Iterator it = interfaces.iterator(); it.hasNext(); )
2603 {
2604 Class intface = (Class) it.next();
2605
2606 if ( isInherited( intface, javaMethod ) )
2607 {
2608 return true;
2609 }
2610 }
2611
2612 List classes = ClassUtils.getAllSuperclasses( clazz );
2613 for ( Iterator it = classes.iterator(); it.hasNext(); )
2614 {
2615 Class superClass = (Class) it.next();
2616
2617 if ( isInherited( superClass, javaMethod ) )
2618 {
2619 return true;
2620 }
2621 }
2622
2623 return false;
2624 }
2625
2626
2627
2628
2629
2630
2631
2632
2633 private boolean isInherited( Class clazz, JavaMethod javaMethod )
2634 {
2635 Method[] methods = clazz.getDeclaredMethods();
2636 for ( int i = 0; i < methods.length; i++ )
2637 {
2638 if ( !methods[i].getName().equals( javaMethod.getName() ) )
2639 {
2640 continue;
2641 }
2642
2643 if ( methods[i].getParameterTypes().length != javaMethod.getParameters().length )
2644 {
2645 continue;
2646 }
2647
2648 boolean found = false;
2649 for ( int j = 0; j < methods[i].getParameterTypes().length; j++ )
2650 {
2651 String name1 = methods[i].getParameterTypes()[j].getName();
2652 String name2 = javaMethod.getParameters()[j].getType().getFullQualifiedName();
2653 if ( name1.equals( name2 ) )
2654 {
2655 found = true;
2656 }
2657 else
2658 {
2659 found = found && false;
2660 }
2661 }
2662
2663 return found;
2664 }
2665
2666 return false;
2667 }
2668
2669
2670
2671
2672
2673 private String getDefaultJavadocForType( Type type )
2674 {
2675 StringBuffer sb = new StringBuffer();
2676
2677 if ( !TypeVariable.class.isAssignableFrom( type.getClass() ) && type.isPrimitive() )
2678 {
2679 if ( type.isArray() )
2680 {
2681 sb.append( "an array of " );
2682 }
2683 else
2684 {
2685 sb.append( "a " );
2686 }
2687 sb.append( type.getJavaClass().getFullyQualifiedName() );
2688 sb.append( "." );
2689 return sb.toString();
2690 }
2691
2692 StringBuffer javadocLink = new StringBuffer();
2693 try
2694 {
2695 getClass( type.getJavaClass().getFullyQualifiedName() );
2696
2697 javadocLink.append( "{@link " );
2698 String s = type.getJavaClass().getFullyQualifiedName();
2699 s = StringUtils.replace( s, "$", "." );
2700 javadocLink.append( s );
2701 javadocLink.append( "}" );
2702 }
2703 catch ( Exception e )
2704 {
2705 javadocLink.append( type.getJavaClass().getFullyQualifiedName() );
2706 }
2707
2708 if ( type.isArray() )
2709 {
2710 sb.append( "an array of " );
2711 sb.append( javadocLink.toString() );
2712 sb.append( " objects." );
2713 }
2714 else
2715 {
2716 sb.append( "a " ).append( javadocLink.toString() ).append( " object." );
2717 }
2718
2719 return sb.toString();
2720 }
2721
2722
2723
2724
2725
2726
2727
2728
2729 private boolean isNewClassFromLastVersion( JavaClass javaClass )
2730 {
2731 if ( clirrNewClasses == null )
2732 {
2733 return false;
2734 }
2735
2736 return clirrNewClasses.contains( javaClass.getFullyQualifiedName() );
2737 }
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747 private boolean isNewMethodFromLastRevision( JavaMethod javaMethod )
2748 throws MojoExecutionException
2749 {
2750 if ( clirrNewMethods == null )
2751 {
2752 return false;
2753 }
2754
2755 List clirrMethods = (List) clirrNewMethods.get( javaMethod.getParentClass().getFullyQualifiedName() );
2756 if ( clirrMethods == null )
2757 {
2758 return false;
2759 }
2760
2761 for ( Iterator it = clirrMethods.iterator(); it.hasNext(); )
2762 {
2763
2764 String clirrMethod = (String) it.next();
2765
2766 String retrn = "";
2767 if ( javaMethod.getReturns() != null )
2768 {
2769 retrn = javaMethod.getReturns().getFullQualifiedName();
2770 }
2771 StringBuffer params = new StringBuffer();
2772 JavaParameter[] parameters = javaMethod.getParameters();
2773 for ( int i = 0; i < parameters.length; i++ )
2774 {
2775 params.append( parameters[i].getResolvedValue() );
2776 if ( i < parameters.length - 1 )
2777 {
2778 params.append( ", " );
2779 }
2780 }
2781 if ( ( clirrMethod.indexOf( retrn + " " ) != -1 )
2782 && ( clirrMethod.indexOf( javaMethod.getName() + "(" ) != -1 )
2783 && ( clirrMethod.indexOf( "(" + params.toString() + ")" ) != -1 ) )
2784 {
2785 return true;
2786 }
2787 }
2788
2789 return false;
2790 }
2791
2792
2793
2794
2795
2796
2797
2798
2799 private Class getClass( String className )
2800 throws MojoExecutionException
2801 {
2802 try
2803 {
2804 return ClassUtils.getClass( getProjectClassLoader(), className, false );
2805 }
2806 catch ( ClassNotFoundException e )
2807 {
2808 throw new MojoExecutionException( "ClassNotFoundException: " + e.getMessage(), e );
2809 }
2810 }
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827 private Class getRuntimeExceptionClass( JavaClass currentClass, String exceptionClassName )
2828 {
2829 String[] potentialClassNames =
2830 new String[] { exceptionClassName, currentClass.getPackage().getName() + "." + exceptionClassName,
2831 currentClass.getPackage().getName() + "." + currentClass.getName() + "$" + exceptionClassName,
2832 "java.lang." + exceptionClassName };
2833
2834 Class clazz = null;
2835 for ( int i = 0; i < potentialClassNames.length; i++ )
2836 {
2837 try
2838 {
2839 clazz = getClass( potentialClassNames[i] );
2840 }
2841 catch ( MojoExecutionException e )
2842 {
2843
2844 }
2845 if ( clazz != null && ClassUtils.isAssignable( clazz, RuntimeException.class ) )
2846 {
2847 return clazz;
2848 }
2849 }
2850
2851 return null;
2852 }
2853
2854
2855
2856
2857 private void addSinceClasses( JavaClass javaClass )
2858 {
2859 if ( sinceClasses == null )
2860 {
2861 sinceClasses = new ArrayList();
2862 }
2863 sinceClasses.add( javaClass.getFullyQualifiedName() );
2864 }
2865
2866 private boolean sinceClassesContains( JavaClass javaClass )
2867 {
2868 return sinceClasses.contains( javaClass.getFullyQualifiedName() );
2869 }
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884 private static void writeFile( final File javaFile, final String encoding, final String content )
2885 throws IOException
2886 {
2887 Writer writer = null;
2888 try
2889 {
2890 writer = WriterFactory.newWriter( javaFile, encoding );
2891 writer.write( StringUtils.unifyLineSeparators( content ) );
2892 }
2893 finally
2894 {
2895 IOUtil.close( writer );
2896 }
2897 }
2898
2899
2900
2901
2902
2903 private static String getFullClirrGoal()
2904 {
2905 StringBuffer sb = new StringBuffer();
2906
2907 sb.append( CLIRR_MAVEN_PLUGIN_GROUPID ).append( ":" );
2908 sb.append( CLIRR_MAVEN_PLUGIN_ARTIFACTID ).append( ":" );
2909 String clirrVersion = CLIRR_MAVEN_PLUGIN_VERSION;
2910 InputStream resourceAsStream = null;
2911 try
2912 {
2913 String resource =
2914 "META-INF/maven/" + CLIRR_MAVEN_PLUGIN_GROUPID + "/" + CLIRR_MAVEN_PLUGIN_ARTIFACTID
2915 + "/pom.properties";
2916 resourceAsStream = AbstractFixJavadocMojo.class.getClassLoader().getResourceAsStream( resource );
2917
2918 if ( resourceAsStream != null )
2919 {
2920 Properties properties = new Properties();
2921 properties.load( resourceAsStream );
2922
2923 if ( StringUtils.isNotEmpty( properties.getProperty( "version" ) ) )
2924 {
2925 clirrVersion = properties.getProperty( "version" );
2926 }
2927 }
2928 }
2929 catch ( IOException e )
2930 {
2931
2932 }
2933 finally
2934 {
2935 IOUtil.close( resourceAsStream );
2936 }
2937
2938 sb.append( clirrVersion ).append( ":" );
2939 sb.append( CLIRR_MAVEN_PLUGIN_GOAL );
2940
2941 return sb.toString();
2942 }
2943
2944
2945
2946
2947
2948
2949
2950 private static String getDefaultClassJavadocComment( final JavaClass javaClass )
2951 {
2952 StringBuffer sb = new StringBuffer();
2953
2954 sb.append( "<p>" );
2955 if ( Arrays.asList( javaClass.getModifiers() ).contains( "abstract" ) )
2956 {
2957 sb.append( "Abstract " );
2958 }
2959
2960 sb.append( javaClass.getName() );
2961
2962 if ( !javaClass.isInterface() )
2963 {
2964 sb.append( " class." );
2965 }
2966 else
2967 {
2968 sb.append( " interface." );
2969 }
2970
2971 sb.append( "</p>" );
2972
2973 return sb.toString();
2974 }
2975
2976
2977
2978
2979
2980
2981
2982 private static String getDefaultMethodJavadocComment( final JavaMethod javaMethod )
2983 {
2984 StringBuffer sb = new StringBuffer();
2985
2986 if ( javaMethod.isConstructor() )
2987 {
2988 sb.append( "<p>Constructor for " );
2989 sb.append( javaMethod.getName() ).append( ".</p>" );
2990 return sb.toString();
2991 }
2992
2993 if ( javaMethod.getName().length() > 3
2994 && ( javaMethod.getName().startsWith( "get" ) || javaMethod.getName().startsWith( "set" ) ) )
2995 {
2996 String field = StringUtils.lowercaseFirstLetter( javaMethod.getName().substring( 3 ) );
2997
2998 JavaClass clazz = javaMethod.getParentClass();
2999
3000 if ( clazz.getFieldByName( field ) == null )
3001 {
3002 sb.append( "<p>" ).append( javaMethod.getName() ).append( "</p>" );
3003 return sb.toString();
3004 }
3005
3006 sb.append( "<p>" );
3007 if ( javaMethod.getName().startsWith( "get" ) )
3008 {
3009 sb.append( "Getter " );
3010 }
3011 if ( javaMethod.getName().startsWith( "set" ) )
3012 {
3013 sb.append( "Setter " );
3014 }
3015 sb.append( "for the field <code>" ).append( field ).append( "</code>." );
3016 sb.append( "</p>" );
3017
3018 return sb.toString();
3019 }
3020
3021 sb.append( "<p>" ).append( javaMethod.getName() ).append( "</p>" );
3022
3023 return sb.toString();
3024 }
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041 private static boolean hasInheritedTag( final String content )
3042 {
3043 final String inheritedTagPattern =
3044 "^\\s*(\\/\\*\\*)?(\\s*(\\*)?)*(\\{)@inheritDoc\\s*(\\})(\\s*(\\*)?)*(\\*\\/)?$";
3045 return Pattern.matches( inheritedTagPattern, StringUtils.removeDuplicateWhitespace( content ) );
3046 }
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086 private static String getJavadocComment( final String javaClassContent, final AbstractJavaEntity entity )
3087 throws IOException
3088 {
3089 if ( entity.getComment() == null )
3090 {
3091 return "";
3092 }
3093
3094 String originalJavadoc = extractOriginalJavadocContent( javaClassContent, entity );
3095
3096 StringBuffer sb = new StringBuffer();
3097 BufferedReader lr = new BufferedReader( new StringReader( originalJavadoc ) );
3098 String line;
3099 while ( ( line = lr.readLine() ) != null )
3100 {
3101 if ( StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith( "* @" )
3102 || StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith( "*@" ) )
3103 {
3104 break;
3105 }
3106 sb.append( line ).append( EOL );
3107 }
3108
3109 return trimRight( sb.toString() );
3110 }
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152 private static String getJavadocComment( final String javaClassContent,
3153 final AbstractInheritableJavaEntity entity, final DocletTag docletTag )
3154 throws IOException
3155 {
3156 if ( docletTag.getValue() == null )
3157 {
3158 return "";
3159 }
3160 if ( docletTag.getParameters().length == 0 )
3161 {
3162 return "";
3163 }
3164
3165 String originalJavadoc = extractOriginalJavadocContent( javaClassContent, entity );
3166
3167 String[] params = fixQdox173( docletTag.getParameters() );
3168 String paramValue = params[0];
3169
3170 StringBuffer sb = new StringBuffer();
3171 BufferedReader lr = new BufferedReader( new StringReader( originalJavadoc ) );
3172 String line;
3173 boolean found = false;
3174 while ( ( line = lr.readLine() ) != null )
3175 {
3176 if ( StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith(
3177 "* @" + docletTag.getName()
3178 + " " + paramValue )
3179 || StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith(
3180 "*@" + docletTag.getName()
3181 + " " + paramValue ) )
3182 {
3183 sb.append( line ).append( EOL );
3184 found = true;
3185 }
3186 else
3187 {
3188 if ( StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith( "* @" )
3189 || StringUtils.removeDuplicateWhitespace( line.trim() ).startsWith( "*@" ) )
3190 {
3191 found = false;
3192 }
3193 if ( found )
3194 {
3195 sb.append( line ).append( EOL );
3196 }
3197 }
3198 }
3199
3200 return trimRight( sb.toString() );
3201 }
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248 private static String extractOriginalJavadoc( final String javaClassContent, final AbstractJavaEntity entity )
3249 throws IOException
3250 {
3251 if ( entity.getComment() == null )
3252 {
3253 return "";
3254 }
3255
3256 String[] javaClassContentLines = getLines( javaClassContent );
3257 List list = new LinkedList();
3258 for ( int i = entity.getLineNumber() - 2; i >= 0; i-- )
3259 {
3260 String line = javaClassContentLines[i];
3261
3262 list.add( trimRight( line ) );
3263 if ( line.trim().startsWith( START_JAVADOC ) )
3264 {
3265 break;
3266 }
3267 }
3268
3269 Collections.reverse( list );
3270
3271 return StringUtils.join( list.iterator(), EOL );
3272 }
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315 private static String extractOriginalJavadocContent( final String javaClassContent,
3316 final AbstractJavaEntity entity )
3317 throws IOException
3318 {
3319 if ( entity.getComment() == null )
3320 {
3321 return "";
3322 }
3323
3324 String originalJavadoc = extractOriginalJavadoc( javaClassContent, entity );
3325 if ( originalJavadoc.indexOf( START_JAVADOC ) != -1 )
3326 {
3327 originalJavadoc =
3328 originalJavadoc.substring( originalJavadoc.indexOf( START_JAVADOC ) + START_JAVADOC.length() );
3329 }
3330 if ( originalJavadoc.indexOf( END_JAVADOC ) != -1 )
3331 {
3332 originalJavadoc = originalJavadoc.substring( 0, originalJavadoc.indexOf( END_JAVADOC ) );
3333 }
3334 if ( originalJavadoc.startsWith( "\r\n" ) )
3335 {
3336 originalJavadoc = originalJavadoc.substring( 2 );
3337 }
3338 else if ( originalJavadoc.startsWith( "\n" ) || originalJavadoc.startsWith( "\r" ) )
3339 {
3340 originalJavadoc = originalJavadoc.substring( 1 );
3341 }
3342
3343 return trimRight( originalJavadoc );
3344 }
3345
3346
3347
3348
3349
3350
3351
3352 private static String removeLastEmptyJavadocLines( final String content )
3353 throws IOException
3354 {
3355 if ( content.indexOf( EOL ) == -1 )
3356 {
3357 return content;
3358 }
3359
3360 String[] lines = getLines( content );
3361 if ( lines.length == 1 )
3362 {
3363 return content;
3364 }
3365
3366 List linesList = new LinkedList();
3367 linesList.addAll( Arrays.asList( lines ) );
3368
3369 Collections.reverse( linesList );
3370
3371 for ( Iterator it = linesList.iterator(); it.hasNext(); )
3372 {
3373 String line = (String) it.next();
3374
3375 if ( line.trim().equals( "*" ) )
3376 {
3377 it.remove();
3378 }
3379 else
3380 {
3381 break;
3382 }
3383 }
3384
3385 Collections.reverse( linesList );
3386
3387 return StringUtils.join( linesList.iterator(), EOL );
3388 }
3389
3390
3391
3392
3393
3394
3395
3396 private static String alignIndentationJavadocLines( final String content, final String indent )
3397 throws IOException
3398 {
3399 String[] lines = getLines( content );
3400
3401 StringBuffer sb = new StringBuffer();
3402 for ( int i = 0; i < lines.length; i++ )
3403 {
3404 String line = lines[i];
3405 if ( !line.trim().startsWith( "*" ) )
3406 {
3407 line = "*" + line;
3408 }
3409 sb.append( indent ).append( " " ).append( trimLeft( line ) );
3410 if ( i < lines.length - 1 )
3411 {
3412 sb.append( EOL );
3413 }
3414 }
3415
3416 return sb.toString();
3417 }
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431 private static String autodetectIndentation( final String line )
3432 {
3433 if ( StringUtils.isEmpty( line ) )
3434 {
3435 return "";
3436 }
3437
3438 return line.substring( 0, line.indexOf( trimLeft( line ) ) );
3439 }
3440
3441
3442
3443
3444
3445
3446 private static String[] getLines( final String content )
3447 throws IOException
3448 {
3449 List lines = new LinkedList();
3450
3451 BufferedReader reader = new BufferedReader( new StringReader( content ) );
3452 String line = reader.readLine();
3453 while ( line != null )
3454 {
3455 lines.add( line );
3456 line = reader.readLine();
3457 }
3458
3459 return (String[]) lines.toArray( new String[0] );
3460 }
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476 private static String trimLeft( final String text )
3477 {
3478 if ( StringUtils.isEmpty( text ) || StringUtils.isEmpty( text.trim() ) )
3479 {
3480 return "";
3481 }
3482
3483 String textTrimmed = text.trim();
3484 return text.substring( text.indexOf( textTrimmed ), text.length() );
3485 }
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500 private static String trimRight( final String text )
3501 {
3502 if ( StringUtils.isEmpty( text ) || StringUtils.isEmpty( text.trim() ) )
3503 {
3504 return "";
3505 }
3506
3507 String textTrimmed = text.trim();
3508 return text.substring( 0, text.indexOf( textTrimmed ) + textTrimmed.length() );
3509 }
3510
3511
3512
3513
3514
3515
3516
3517 private static String[] fixQdox173( String[] params )
3518 {
3519 if ( params == null || params.length == 0 )
3520 {
3521 return params;
3522 }
3523 if ( params.length < 3 )
3524 {
3525 return params;
3526 }
3527
3528 if ( params[0].trim().equals( "<" ) && params[2].trim().equals( ">" ) )
3529 {
3530 String param = params[1];
3531 List l = new ArrayList( Arrays.asList( params ) );
3532 l.set( 1, "<" + param + ">" );
3533 l.remove( 0 );
3534 l.remove( 1 );
3535
3536 return (String[]) l.toArray( new String[0] );
3537 }
3538
3539 return params;
3540 }
3541
3542
3543
3544
3545 private class JavaEntityTags
3546 {
3547 private final AbstractInheritableJavaEntity entity;
3548
3549 private final boolean isJavaMethod;
3550
3551
3552 private List namesTags;
3553
3554
3555 private Map tagParams;
3556
3557
3558 private String tagReturn;
3559
3560
3561 private Map tagThrows;
3562
3563
3564 private List unknownsTags;
3565
3566 public JavaEntityTags( AbstractInheritableJavaEntity entity, boolean isJavaMethod )
3567 {
3568 this.entity = entity;
3569 this.isJavaMethod = isJavaMethod;
3570 this.namesTags = new LinkedList();
3571 this.tagParams = new LinkedHashMap();
3572 this.tagThrows = new LinkedHashMap();
3573 this.unknownsTags = new LinkedList();
3574 }
3575
3576 public List getNamesTags()
3577 {
3578 return namesTags;
3579 }
3580
3581 public String getJavadocReturnTag()
3582 {
3583 return tagReturn;
3584 }
3585
3586 public void setJavadocReturnTag( String s )
3587 {
3588 tagReturn = s;
3589 }
3590
3591 public List getUnknownTags()
3592 {
3593 return unknownsTags;
3594 }
3595
3596 public void putJavadocParamTag( String paramName, String originalJavadocTag )
3597 {
3598 tagParams.put( paramName, originalJavadocTag );
3599 }
3600
3601 public String getJavadocParamTag( String paramName )
3602 {
3603 return getJavadocParamTag( paramName, false );
3604 }
3605
3606 public String getJavadocParamTag( String paramName, boolean nullable )
3607 {
3608 String originalJavadocTag = (String) tagParams.get( paramName );
3609 if ( !nullable && originalJavadocTag == null && getLog().isWarnEnabled() )
3610 {
3611 getLog().warn( getMessage( paramName, "javaEntityTags.tagParams" ) );
3612 }
3613
3614 return originalJavadocTag;
3615 }
3616
3617 public void putJavadocThrowsTag( String paramName, String originalJavadocTag )
3618 {
3619 tagThrows.put( paramName, originalJavadocTag );
3620 }
3621
3622 public String getJavadocThrowsTag( String paramName )
3623 {
3624 return getJavadocThrowsTag( paramName, false );
3625 }
3626
3627 public String getJavadocThrowsTag( String paramName, boolean nullable )
3628 {
3629 String originalJavadocTag = (String) tagThrows.get( paramName );
3630 if ( !nullable && originalJavadocTag == null && getLog().isWarnEnabled() )
3631 {
3632 getLog().warn( getMessage( paramName, "javaEntityTags.tagThrows" ) );
3633 }
3634
3635 return originalJavadocTag;
3636 }
3637
3638 private String getMessage( String paramName, String mapName )
3639 {
3640 StringBuffer msg = new StringBuffer();
3641 msg.append( "No param '" ).append( paramName );
3642 msg.append( "' key found in " + mapName + " for the entity: " );
3643 if ( isJavaMethod )
3644 {
3645 JavaMethod javaMethod = (JavaMethod) entity;
3646 msg.append( getJavaMethodAsString( javaMethod ) );
3647 }
3648 else
3649 {
3650 JavaClass javaClass = (JavaClass) entity;
3651 msg.append( javaClass.getFullyQualifiedName() );
3652 }
3653
3654 return msg.toString();
3655 }
3656
3657
3658 public String toString()
3659 {
3660 StringBuffer sb = new StringBuffer();
3661
3662 sb.append( "namesTags=" ).append( namesTags ).append( "\n" );
3663 sb.append( "tagParams=" ).append( tagParams ).append( "\n" );
3664 sb.append( "tagReturn=" ).append( tagReturn ).append( "\n" );
3665 sb.append( "tagThrows=" ).append( tagThrows ).append( "\n" );
3666 sb.append( "unknownsTags=" ).append( unknownsTags ).append( "\n" );
3667
3668 return sb.toString();
3669 }
3670 }
3671 }