View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2026 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.javadoc;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.nio.file.Files;
25  import java.nio.file.Path;
26  import java.util.HashSet;
27  import java.util.Set;
28  
29  import com.puppycrawl.tools.checkstyle.GlobalStatefulCheck;
30  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
31  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
32  import com.puppycrawl.tools.checkstyle.api.FileText;
33  
34  /**
35   * <div>
36   * Checks that each Java package has a Javadoc file used for commenting.
37   * By default, it only allows a {@code package-info.java} file,
38   * but can be configured to allow a {@code package.html} file.
39   * </div>
40   *
41   * <p>
42   * A violation will be reported if both files exist as this is not allowed by the Javadoc tool.
43   * </p>
44   *
45   * @since 5.0
46   */
47  @GlobalStatefulCheck
48  public class JavadocPackageCheck extends AbstractFileSetCheck {
49  
50      /**
51       * A key is pointing to the warning message text in "messages.properties"
52       * file.
53       */
54      public static final String MSG_LEGACY_PACKAGE_HTML = "javadoc.legacyPackageHtml";
55  
56      /**
57       * A key is pointing to the warning message text in "messages.properties"
58       * file.
59       */
60      public static final String MSG_PACKAGE_INFO = "javadoc.packageInfo";
61  
62      /** The directories checked. */
63      private final Set<File> directoriesChecked = new HashSet<>();
64  
65      /** Allow legacy {@code package.html} file to be used. */
66      private boolean allowLegacy;
67  
68      /**
69       * Creates a new instance.
70       */
71      public JavadocPackageCheck() {
72          // java, not html!
73          // The rule is: Every JAVA file should have a package.html sibling
74          setFileExtensions("java");
75      }
76  
77      /**
78       * Setter to specify the file extensions of the files to process.
79       *
80       * @param extensions the set of file extensions. A missing
81       *         initial '.' character of an extension is automatically added.
82       * @throws IllegalArgumentException is argument is null
83       */
84      @Override
85      public final void setFileExtensions(String... extensions) {
86          super.setFileExtensions(extensions);
87      }
88  
89      @Override
90      protected void processFiltered(File file, FileText fileText) throws CheckstyleException {
91          // module-info.java is not a package member.
92          if (!"module-info.java".equals(file.getName())) {
93              // Check if already processed directory
94              final File dir;
95              try {
96                  dir = file.getCanonicalFile().getParentFile();
97              }
98              catch (IOException exc) {
99                  throw new CheckstyleException(
100                         "Exception while getting canonical path to file " + file.getPath(), exc);
101             }
102             final boolean isDirChecked = !directoriesChecked.add(dir);
103             if (!isDirChecked) {
104                 // Check for the preferred file.
105                 final Path packageInfo = Path.of(dir.getPath(), "package-info.java");
106                 final Path packageHtml = Path.of(dir.getPath(), "package.html");
107 
108                 if (Files.exists(packageInfo)) {
109                     if (Files.exists(packageHtml)) {
110                         log(1, MSG_LEGACY_PACKAGE_HTML);
111                     }
112                 }
113                 else if (!allowLegacy || !Files.exists(packageHtml)) {
114                     log(1, MSG_PACKAGE_INFO);
115                 }
116             }
117         }
118     }
119 
120     /**
121      * Setter to allow legacy {@code package.html} file to be used.
122      *
123      * @param allowLegacy whether to allow support.
124      * @since 5.0
125      */
126     public void setAllowLegacy(boolean allowLegacy) {
127         this.allowLegacy = allowLegacy;
128     }
129 
130 }