001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2022 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.metrics; 021 022import com.puppycrawl.tools.checkstyle.api.TokenTypes; 023 024/** 025 * <p> 026 * Measures the number of instantiations of other classes 027 * within the given class or record. This type of coupling is not caused by inheritance or 028 * the object oriented paradigm. Generally speaking, any data type with other 029 * data types as members or local variable that is an instantiation (object) 030 * of another class has data abstraction coupling (DAC). The higher the DAC, 031 * the more complex the structure of the class. 032 * </p> 033 * <p> 034 * This check processes files in the following way: 035 * </p> 036 * <ol> 037 * <li> 038 * Iterates over the list of tokens (defined below) and counts all mentioned classes. 039 * <ul> 040 * <li> 041 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#IMPORT"> 042 * PACKAGE_DEF</a> 043 * </li> 044 * <li> 045 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#IMPORT"> 046 * IMPORT</a> 047 * </li> 048 * <li> 049 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 050 * CLASS_DEF</a> 051 * </li> 052 * <li> 053 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 054 * INTERFACE_DEF</a> 055 * </li> 056 * <li> 057 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF"> 058 * ENUM_DEF</a> 059 * </li> 060 * <li> 061 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#LITERAL_NEW"> 062 * LITERAL_NEW</a> 063 * </li> 064 * <li> 065 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF"> 066 * RECORD_DEF</a> 067 * </li> 068 * </ul> 069 * </li> 070 * <li> 071 * If a class was imported with direct import (i.e. {@code import java.math.BigDecimal}), 072 * or the class was referenced with the package name (i.e. {@code java.math.BigDecimal value}) 073 * and the package was added to the {@code excludedPackages} parameter, the class 074 * does not increase complexity. 075 * </li> 076 * <li> 077 * If a class name was added to the {@code excludedClasses} parameter, 078 * the class does not increase complexity. 079 * </li> 080 * </ol> 081 * <ul> 082 * <li> 083 * Property {@code max} - Specify the maximum threshold allowed. 084 * Type is {@code int}. 085 * Default value is {@code 7}. 086 * </li> 087 * <li> 088 * Property {@code excludedClasses} - Specify user-configured class names to ignore. 089 * Type is {@code java.lang.String[]}. 090 * Default value is {@code ArrayIndexOutOfBoundsException, ArrayList, Boolean, Byte, 091 * Character, Class, Collection, Deprecated, Deque, Double, DoubleStream, EnumSet, Exception, 092 * Float, FunctionalInterface, HashMap, HashSet, IllegalArgumentException, IllegalStateException, 093 * IndexOutOfBoundsException, IntStream, Integer, LinkedHashMap, LinkedHashSet, LinkedList, List, 094 * Long, LongStream, Map, NullPointerException, Object, Optional, OptionalDouble, OptionalInt, 095 * OptionalLong, Override, Queue, RuntimeException, SafeVarargs, SecurityException, Set, Short, 096 * SortedMap, SortedSet, Stream, String, StringBuffer, StringBuilder, SuppressWarnings, Throwable, 097 * TreeMap, TreeSet, UnsupportedOperationException, Void, boolean, byte, char, double, 098 * float, int, long, short, var, void}. 099 * </li> 100 * <li> 101 * Property {@code excludeClassesRegexps} - Specify user-configured regular 102 * expressions to ignore classes. 103 * Type is {@code java.util.regex.Pattern[]}. 104 * Default value is {@code ^$}. 105 * </li> 106 * <li> 107 * Property {@code excludedPackages} - Specify user-configured packages to ignore. 108 * Type is {@code java.lang.String[]}. 109 * Default value is {@code ""}. 110 * </li> 111 * </ul> 112 * <p> 113 * To configure the check: 114 * </p> 115 * <pre> 116 * <module name="ClassDataAbstractionCoupling"/> 117 * </pre> 118 * <p> 119 * Example: 120 * </p> 121 * <p> 122 * The check passes without violations in the following: 123 * </p> 124 * <pre> 125 * class InputClassCoupling { 126 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 127 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 128 * Date date = new Date(); // Counted, 1 129 * Time time = new Time(); // Counted, 2 130 * Place place = new Place(); // Counted, 3 131 * } 132 * </pre> 133 * <p> 134 * The check results in a violation in the following: 135 * </p> 136 * <pre> 137 * class InputClassCoupling { 138 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 139 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 140 * Date date = new Date(); // Counted, 1 141 * Time time = new Time(); // Counted, 2 142 * // instantiation of 5 other user defined classes 143 * Place place = new Place(); // violation, total is 8 144 * } 145 * </pre> 146 * <p> 147 * To configure the check with a threshold of 2: 148 * </p> 149 * <pre> 150 * <module name="ClassDataAbstractionCoupling"> 151 * <property name="max" value="2"/> 152 * </module> 153 * </pre> 154 * <p> 155 * Example: 156 * </p> 157 * <p> 158 * The check passes without violations in the following: 159 * </p> 160 * <pre> 161 * class InputClassCoupling { 162 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 163 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 164 * Date date = new Date(); // Counted, 1 165 * Time time = new Time(); // Counted, 2 166 * } 167 * </pre> 168 * <p> 169 * The check results in a violation in the following: 170 * </p> 171 * <pre> 172 * class InputClassCoupling { 173 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 174 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 175 * Date date = new Date(); // Counted, 1 176 * Time time = new Time(); // Counted, 2 177 * Place place = new Place(); // violation, total is 3 178 * } 179 * </pre> 180 * <p> 181 * To configure the check with three excluded classes {@code HashMap}, 182 * {@code HashSet} and {@code Place}: 183 * </p> 184 * <pre> 185 * <module name="ClassDataAbstractionCoupling"> 186 * <property name="excludedClasses" value="HashMap, HashSet, Place"/> 187 * </module> 188 * </pre> 189 * <p> 190 * Example: 191 * </p> 192 * <p> 193 * The check passes without violations in the following: 194 * </p> 195 * <pre> 196 * class InputClassCoupling { 197 * Set set = new HashSet(); // Ignored 198 * Map map = new HashMap(); // Ignored 199 * Date date = new Date(); // Counted, 1 200 * Time time = new Time(); // Counted, 2 201 * // instantiation of 5 other user defined classes 202 * Place place = new Place(); // Ignored 203 * } 204 * </pre> 205 * <p> 206 * The check results in a violation in the following: 207 * </p> 208 * <pre> 209 * class InputClassCoupling { 210 * Set set = new HashSet(); // Ignored 211 * Map map = new HashMap(); // Ignored 212 * Date date = new Date(); // Counted, 1 213 * Time time = new Time(); // Counted, 2 214 * // instantiation of 5 other user defined classes 215 * Space space = new Space(); // violation, total is 8 216 * } 217 * </pre> 218 * <p> 219 * To configure the check to exclude classes with a regular expression 220 * {@code .*Reader$}: 221 * </p> 222 * <pre> 223 * <module name="ClassDataAbstractionCoupling"> 224 * <property name="excludeClassesRegexps" value=".*Reader$"/> 225 * </module> 226 * </pre> 227 * <p> 228 * Example: 229 * </p> 230 * <p> 231 * The check passes without violations in the following: 232 * </p> 233 * <pre> 234 * class InputClassCoupling { 235 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 236 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 237 * Date date = new Date(); // Counted, 1 238 * Time time = new Time(); // Counted, 2 239 * // instantiation of 5 other user defined classes 240 * BufferedReader br = new BufferedReader(); // Ignored 241 * } 242 * </pre> 243 * <p> 244 * The check results in a violation in the following: 245 * </p> 246 * <pre> 247 * class InputClassCoupling { 248 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 249 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 250 * Date date = new Date(); // Counted, 1 251 * Time time = new Time(); // Counted, 2 252 * // instantiation of 5 other user defined classes 253 * File file = new File(); // violation, total is 8 254 * } 255 * </pre> 256 * <p> 257 * To configure the check with an excluded package {@code java.io}: 258 * </p> 259 * <pre> 260 * <module name="ClassDataAbstractionCoupling"> 261 * <property name="excludedPackages" value="java.io"/> 262 * </module> 263 * </pre> 264 * <p> 265 * Example: 266 * </p> 267 * <p> 268 * The check passes without violations in the following: 269 * </p> 270 * <pre> 271 * import java.io.BufferedReader; 272 * 273 * class InputClassCoupling { 274 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 275 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 276 * Date date = new Date(); // Counted, 1 277 * Time time = new Time(); // Counted, 2 278 * // instantiation of 5 other user defined classes 279 * BufferedReader br = new BufferedReader(); // Ignored 280 * } 281 * </pre> 282 * <p> 283 * The check results in a violation in the following: 284 * </p> 285 * <pre> 286 * import java.util.StringTokenizer; 287 * 288 * class InputClassCoupling { 289 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 290 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 291 * Date date = new Date(); // Counted, 1 292 * Time time = new Time(); // Counted, 2 293 * // instantiation of 5 other user defined classes 294 * StringTokenizer st = new StringTokenizer(); // violation, total is 8 295 * } 296 * </pre> 297 * <p> 298 * Override property {@code excludedPackages} to mark some packages as excluded. 299 * Each member of {@code excludedPackages} should be a valid identifier: 300 * </p> 301 * <ul> 302 * <li> 303 * {@code java.util} - valid, excludes all classes inside {@code java.util}, 304 * but not from the subpackages. 305 * </li> 306 * <li> 307 * {@code java.util.} - invalid, should not end with a dot. 308 * </li> 309 * <li> 310 * {@code java.util.*} - invalid, should not end with a star. 311 * </li> 312 * </ul> 313 * <p> 314 * Note, that checkstyle will ignore all classes from the {@code java.lang} 315 * package and its subpackages, even if the {@code java.lang} was not listed 316 * in the {@code excludedPackages} parameter. 317 * </p> 318 * <p> 319 * Also note, that {@code excludedPackages} will not exclude classes, imported 320 * via wildcard (e.g. {@code import java.math.*}). Instead of wildcard import 321 * you should use direct import (e.g. {@code import java.math.BigDecimal}). 322 * </p> 323 * <p> 324 * Also note, that checkstyle will not exclude classes within the same file 325 * even if it was listed in the {@code excludedPackages} parameter. 326 * For example, assuming the config is 327 * </p> 328 * <pre> 329 * <module name="ClassDataAbstractionCoupling"> 330 * <property name="excludedPackages" value="a.b"/> 331 * </module> 332 * </pre> 333 * <p> 334 * And the file {@code a.b.Foo.java} is: 335 * </p> 336 * <pre> 337 * package a.b; 338 * 339 * import a.b.Bar; 340 * import a.b.c.Baz; 341 * 342 * class Foo { 343 * Bar bar; // Will be ignored, located inside ignored a.b package 344 * Baz baz; // Will not be ignored, located inside a.b.c package 345 * Data data; // Will not be ignored, same file 346 * 347 * class Data { 348 * Foo foo; // Will not be ignored, same file 349 * } 350 * } 351 * </pre> 352 * <p> 353 * The {@code bar} member will not be counted, since the {@code a.b} added 354 * to the {@code excludedPackages}. The {@code baz} member will be counted, 355 * since the {@code a.b.c} was not added to the {@code excludedPackages}. 356 * The {@code data} and {@code foo} members will be counted, as they are inside same file. 357 * </p> 358 * <p> 359 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 360 * </p> 361 * <p> 362 * Violation Message Keys: 363 * </p> 364 * <ul> 365 * <li> 366 * {@code classDataAbstractionCoupling} 367 * </li> 368 * </ul> 369 * 370 * @since 3.4 371 * 372 */ 373public final class ClassDataAbstractionCouplingCheck 374 extends AbstractClassCouplingCheck { 375 376 /** 377 * A key is pointing to the warning message text in "messages.properties" 378 * file. 379 */ 380 public static final String MSG_KEY = "classDataAbstractionCoupling"; 381 382 /** Default allowed complexity. */ 383 private static final int DEFAULT_MAX = 7; 384 385 /** Creates bew instance of the check. */ 386 public ClassDataAbstractionCouplingCheck() { 387 super(DEFAULT_MAX); 388 } 389 390 @Override 391 public int[] getRequiredTokens() { 392 return new int[] { 393 TokenTypes.PACKAGE_DEF, 394 TokenTypes.IMPORT, 395 TokenTypes.CLASS_DEF, 396 TokenTypes.INTERFACE_DEF, 397 TokenTypes.ENUM_DEF, 398 TokenTypes.LITERAL_NEW, 399 TokenTypes.RECORD_DEF, 400 }; 401 } 402 403 @Override 404 public int[] getAcceptableTokens() { 405 return getRequiredTokens(); 406 } 407 408 @Override 409 protected String getLogMessageId() { 410 return MSG_KEY; 411 } 412 413}