001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 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.lang.String[]}. 104 * Validation type is {@code java.util.regex.Pattern}. 105 * Default value is {@code ^$}. 106 * </li> 107 * <li> 108 * Property {@code excludedPackages} - Specify user-configured packages to ignore. 109 * Type is {@code java.lang.String[]}. 110 * Default value is {@code ""}. 111 * </li> 112 * </ul> 113 * <p> 114 * To configure the check: 115 * </p> 116 * <pre> 117 * <module name="ClassDataAbstractionCoupling"/> 118 * </pre> 119 * <p> 120 * Example: 121 * </p> 122 * <p> 123 * The check passes without violations in the following: 124 * </p> 125 * <pre> 126 * class InputClassCoupling { 127 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 128 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 129 * Date date = new Date(); // Counted, 1 130 * Time time = new Time(); // Counted, 2 131 * Place place = new Place(); // Counted, 3 132 * } 133 * </pre> 134 * <p> 135 * The check results in a violation in the following: 136 * </p> 137 * <pre> 138 * class InputClassCoupling { 139 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 140 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 141 * Date date = new Date(); // Counted, 1 142 * Time time = new Time(); // Counted, 2 143 * // instantiation of 5 other user defined classes 144 * Place place = new Place(); // violation, total is 8 145 * } 146 * </pre> 147 * <p> 148 * To configure the check with a threshold of 2: 149 * </p> 150 * <pre> 151 * <module name="ClassDataAbstractionCoupling"> 152 * <property name="max" value="2"/> 153 * </module> 154 * </pre> 155 * <p> 156 * Example: 157 * </p> 158 * <p> 159 * The check passes without violations in the following: 160 * </p> 161 * <pre> 162 * class InputClassCoupling { 163 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 164 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 165 * Date date = new Date(); // Counted, 1 166 * Time time = new Time(); // Counted, 2 167 * } 168 * </pre> 169 * <p> 170 * The check results in a violation in the following: 171 * </p> 172 * <pre> 173 * class InputClassCoupling { 174 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 175 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 176 * Date date = new Date(); // Counted, 1 177 * Time time = new Time(); // Counted, 2 178 * Place place = new Place(); // violation, total is 3 179 * } 180 * </pre> 181 * <p> 182 * To configure the check with three excluded classes {@code HashMap}, 183 * {@code HashSet} and {@code Place}: 184 * </p> 185 * <pre> 186 * <module name="ClassDataAbstractionCoupling"> 187 * <property name="excludedClasses" value="HashMap, HashSet, Place"/> 188 * </module> 189 * </pre> 190 * <p> 191 * Example: 192 * </p> 193 * <p> 194 * The check passes without violations in the following: 195 * </p> 196 * <pre> 197 * class InputClassCoupling { 198 * Set set = new HashSet(); // Ignored 199 * Map map = new HashMap(); // Ignored 200 * Date date = new Date(); // Counted, 1 201 * Time time = new Time(); // Counted, 2 202 * // instantiation of 5 other user defined classes 203 * Place place = new Place(); // Ignored 204 * } 205 * </pre> 206 * <p> 207 * The check results in a violation in the following: 208 * </p> 209 * <pre> 210 * class InputClassCoupling { 211 * Set set = new HashSet(); // Ignored 212 * Map map = new HashMap(); // Ignored 213 * Date date = new Date(); // Counted, 1 214 * Time time = new Time(); // Counted, 2 215 * // instantiation of 5 other user defined classes 216 * Space space = new Space(); // violation, total is 8 217 * } 218 * </pre> 219 * <p> 220 * To configure the check to exclude classes with a regular expression 221 * {@code .*Reader$}: 222 * </p> 223 * <pre> 224 * <module name="ClassDataAbstractionCoupling"> 225 * <property name="excludeClassesRegexps" value=".*Reader$"/> 226 * </module> 227 * </pre> 228 * <p> 229 * Example: 230 * </p> 231 * <p> 232 * The check passes without violations in the following: 233 * </p> 234 * <pre> 235 * class InputClassCoupling { 236 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 237 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 238 * Date date = new Date(); // Counted, 1 239 * Time time = new Time(); // Counted, 2 240 * // instantiation of 5 other user defined classes 241 * BufferedReader br = new BufferedReader(); // Ignored 242 * } 243 * </pre> 244 * <p> 245 * The check results in a violation in the following: 246 * </p> 247 * <pre> 248 * class InputClassCoupling { 249 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 250 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 251 * Date date = new Date(); // Counted, 1 252 * Time time = new Time(); // Counted, 2 253 * // instantiation of 5 other user defined classes 254 * File file = new File(); // violation, total is 8 255 * } 256 * </pre> 257 * <p> 258 * To configure the check with an excluded package {@code java.io}: 259 * </p> 260 * <pre> 261 * <module name="ClassDataAbstractionCoupling"> 262 * <property name="excludedPackages" value="java.io"/> 263 * </module> 264 * </pre> 265 * <p> 266 * Example: 267 * </p> 268 * <p> 269 * The check passes without violations in the following: 270 * </p> 271 * <pre> 272 * import java.io.BufferedReader; 273 * 274 * class InputClassCoupling { 275 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 276 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 277 * Date date = new Date(); // Counted, 1 278 * Time time = new Time(); // Counted, 2 279 * // instantiation of 5 other user defined classes 280 * BufferedReader br = new BufferedReader(); // Ignored 281 * } 282 * </pre> 283 * <p> 284 * The check results in a violation in the following: 285 * </p> 286 * <pre> 287 * import java.util.StringTokenizer; 288 * 289 * class InputClassCoupling { 290 * Set set = new HashSet(); // HashSet ignored due to default excludedClasses property 291 * Map map = new HashMap(); // HashMap ignored due to default excludedClasses property 292 * Date date = new Date(); // Counted, 1 293 * Time time = new Time(); // Counted, 2 294 * // instantiation of 5 other user defined classes 295 * StringTokenizer st = new StringTokenizer(); // violation, total is 8 296 * } 297 * </pre> 298 * <p> 299 * Override property {@code excludedPackages} to mark some packages as excluded. 300 * Each member of {@code excludedPackages} should be a valid identifier: 301 * </p> 302 * <ul> 303 * <li> 304 * {@code java.util} - valid, excludes all classes inside {@code java.util}, 305 * but not from the subpackages. 306 * </li> 307 * <li> 308 * {@code java.util.} - invalid, should not end with a dot. 309 * </li> 310 * <li> 311 * {@code java.util.*} - invalid, should not end with a star. 312 * </li> 313 * </ul> 314 * <p> 315 * Note, that checkstyle will ignore all classes from the {@code java.lang} 316 * package and its subpackages, even if the {@code java.lang} was not listed 317 * in the {@code excludedPackages} parameter. 318 * </p> 319 * <p> 320 * Also note, that {@code excludedPackages} will not exclude classes, imported 321 * via wildcard (e.g. {@code import java.math.*}). Instead of wildcard import 322 * you should use direct import (e.g. {@code import java.math.BigDecimal}). 323 * </p> 324 * <p> 325 * Also note, that checkstyle will not exclude classes within the same file 326 * even if it was listed in the {@code excludedPackages} parameter. 327 * For example, assuming the config is 328 * </p> 329 * <pre> 330 * <module name="ClassDataAbstractionCoupling"> 331 * <property name="excludedPackages" value="a.b"/> 332 * </module> 333 * </pre> 334 * <p> 335 * And the file {@code a.b.Foo.java} is: 336 * </p> 337 * <pre> 338 * package a.b; 339 * 340 * import a.b.Bar; 341 * import a.b.c.Baz; 342 * 343 * class Foo { 344 * Bar bar; // Will be ignored, located inside ignored a.b package 345 * Baz baz; // Will not be ignored, located inside a.b.c package 346 * Data data; // Will not be ignored, same file 347 * 348 * class Data { 349 * Foo foo; // Will not be ignored, same file 350 * } 351 * } 352 * </pre> 353 * <p> 354 * The {@code bar} member will not be counted, since the {@code a.b} added 355 * to the {@code excludedPackages}. The {@code baz} member will be counted, 356 * since the {@code a.b.c} was not added to the {@code excludedPackages}. 357 * The {@code data} and {@code foo} members will be counted, as they are inside same file. 358 * </p> 359 * <p> 360 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 361 * </p> 362 * <p> 363 * Violation Message Keys: 364 * </p> 365 * <ul> 366 * <li> 367 * {@code classDataAbstractionCoupling} 368 * </li> 369 * </ul> 370 * 371 * @since 3.4 372 * 373 */ 374public final class ClassDataAbstractionCouplingCheck 375 extends AbstractClassCouplingCheck { 376 377 /** 378 * A key is pointing to the warning message text in "messages.properties" 379 * file. 380 */ 381 public static final String MSG_KEY = "classDataAbstractionCoupling"; 382 383 /** Default allowed complexity. */ 384 private static final int DEFAULT_MAX = 7; 385 386 /** Creates bew instance of the check. */ 387 public ClassDataAbstractionCouplingCheck() { 388 super(DEFAULT_MAX); 389 } 390 391 @Override 392 public int[] getRequiredTokens() { 393 return new int[] { 394 TokenTypes.PACKAGE_DEF, 395 TokenTypes.IMPORT, 396 TokenTypes.CLASS_DEF, 397 TokenTypes.INTERFACE_DEF, 398 TokenTypes.ENUM_DEF, 399 TokenTypes.LITERAL_NEW, 400 TokenTypes.RECORD_DEF, 401 }; 402 } 403 404 @Override 405 public int[] getAcceptableTokens() { 406 return getRequiredTokens(); 407 } 408 409 @Override 410 protected String getLogMessageId() { 411 return MSG_KEY; 412 } 413 414}