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