1 /////////////////////////////////////////////////////////////////////////////////////////////// 2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules. 3 // Copyright (C) 2001-2025 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 // Check if already processed directory 92 final File dir; 93 try { 94 dir = file.getCanonicalFile().getParentFile(); 95 } 96 catch (IOException exc) { 97 throw new CheckstyleException( 98 "Exception while getting canonical path to file " + file.getPath(), exc); 99 } 100 final boolean isDirChecked = !directoriesChecked.add(dir); 101 if (!isDirChecked) { 102 // Check for the preferred file. 103 final Path packageInfo = Path.of(dir.getPath(), "package-info.java"); 104 final Path packageHtml = Path.of(dir.getPath(), "package.html"); 105 106 if (Files.exists(packageInfo)) { 107 if (Files.exists(packageHtml)) { 108 log(1, MSG_LEGACY_PACKAGE_HTML); 109 } 110 } 111 else if (!allowLegacy || !Files.exists(packageHtml)) { 112 log(1, MSG_PACKAGE_INFO); 113 } 114 } 115 } 116 117 /** 118 * Setter to allow legacy {@code package.html} file to be used. 119 * 120 * @param allowLegacy whether to allow support. 121 * @since 5.0 122 */ 123 public void setAllowLegacy(boolean allowLegacy) { 124 this.allowLegacy = allowLegacy; 125 } 126 127 }