001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2019 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 * This metric measures the number of instantiations of other classes 027 * within the given class. 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 * </ul> 065 * </li> 066 * <li> 067 * If a class was imported with direct import (i.e. {@code import java.math.BigDecimal}), 068 * or the class was referenced with the package name (i.e. {@code java.math.BigDecimal value}) 069 * and the package was added to the {@code excludedPackages} parameter, the class 070 * does not increase complexity. 071 * </li> 072 * <li> 073 * If a class name was added to the {@code excludedClasses} parameter, 074 * the class does not increase complexity. 075 * </li> 076 * </ol> 077 * <ul> 078 * <li> 079 * Property {@code max} - Specify the maximum threshold allowed. 080 * Default value is {@code 7}. 081 * </li> 082 * <li> 083 * Property {@code excludedClasses} - Specify user-configured class names to ignore. 084 * Default value is {@code ArrayIndexOutOfBoundsException, ArrayList, Boolean, Byte, 085 * Character, Class, Deprecated, Deque, Double, Exception, Float, FunctionalInterface, 086 * HashMap, HashSet, IllegalArgumentException, IllegalStateException, 087 * IndexOutOfBoundsException, Integer, LinkedList, List, Long, Map, NullPointerException, 088 * Object, Override, Queue, RuntimeException, SafeVarargs, SecurityException, Set, Short, 089 * SortedMap, SortedSet, String, StringBuffer, StringBuilder, SuppressWarnings, Throwable, 090 * TreeMap, TreeSet, UnsupportedOperationException, Void, boolean, byte, char, double, 091 * float, int, long, short, void}. 092 * </li> 093 * <li> 094 * Property {@code excludeClassesRegexps} - Specify user-configured regular 095 * expressions to ignore classes. 096 * Default value is {@code ^$}. 097 * </li> 098 * <li> 099 * Property {@code excludedPackages} - Specify user-configured packages to ignore. 100 * Default value is {@code {}}. 101 * </li> 102 * </ul> 103 * <p> 104 * To configure the check: 105 * </p> 106 * <pre> 107 * <module name="ClassDataAbstractionCoupling"/> 108 * </pre> 109 * <p> 110 * To configure the check with a threshold of 5: 111 * </p> 112 * <pre> 113 * <module name="ClassDataAbstractionCoupling"> 114 * <property name="max" value="5"/> 115 * </module> 116 * </pre> 117 * <p> 118 * To configure the check with two excluded classes {@code HashMap} and {@code HashSet}: 119 * </p> 120 * <pre> 121 * <module name="ClassDataAbstractionCoupling"> 122 * <property name="excludedClasses" value="HashMap, HashSet"/> 123 * </module> 124 * </pre> 125 * <p> 126 * To configure the check with two regular expressions {@code ^Array.*} and {@code .*Exception$}: 127 * </p> 128 * <pre> 129 * <module name="ClassDataAbstractionCoupling"> 130 * <property name="excludeClassesRegexps" 131 * value="^Array.*, .*Exception$"/> 132 * </module> 133 * </pre> 134 * <p> 135 * The following example demonstrates usage of <b>excludedClasses</b> and 136 * <b>excludeClassesRegexps</b> properties 137 * </p> 138 * <p> 139 * Expected result is one class {@code Date} 140 * </p> 141 * <pre> 142 * <module name="ClassDataAbstractionCoupling"> 143 * <property name="excludedClasses" value="ArrayList"/> 144 * <property name="excludeClassesRegexps" value="^Hash.*"/> 145 * </module> 146 * </pre> 147 * <pre> 148 * public class InputClassCoupling { 149 * public Set _set = new HashSet(); 150 * public Map _map = new HashMap(); 151 * public List<String> _list = new ArrayList<>(); 152 * public Date _date = new Date(); 153 * } 154 * </pre> 155 * <p> 156 * To configure the check with two excluded classes {@code HashMap} and {@code HashSet}: 157 * </p> 158 * <pre> 159 * <module name="ClassDataAbstractionCoupling"> 160 * <property name="excludedClasses" value="HashMap, HashSet"/> 161 * </module> 162 * </pre> 163 * <p> 164 * To configure the check with two regular expressions {@code ^Array.*} and {@code .*Exception$}: 165 * </p> 166 * <pre> 167 * <module name="ClassDataAbstractionCoupling"> 168 * <property name="excludeClassesRegexps" value="^Array.*, .*Exception$"/> 169 * </module> 170 * </pre> 171 * <p> 172 * The following example demonstrates usage of <b>excludedClasses</b> and 173 * <b>excludeClassesRegexps</b> properties 174 * </p> 175 * <p> 176 * Expected result is one class {@code Date} 177 * </p> 178 * <pre> 179 * <module name="ClassDataAbstractionCoupling"> 180 * <property name="excludedClasses" value="ArrayList"/> 181 * <property name="excludeClassesRegexps" value="^Hash.*"/> 182 * </module> 183 * </pre> 184 * <pre> 185 * public class InputClassCoupling { 186 * public Set _set = new HashSet(); 187 * public Map _map = new HashMap(); 188 * public List<String> _list = new ArrayList<>(); 189 * public Date _date = new Date(); 190 * } 191 * </pre> 192 * <p> 193 * Override property {@code excludedPackages} to mark some packages as excluded. 194 * Each member of {@code excludedPackages} should be a valid identifier: 195 * </p> 196 * <ul> 197 * <li> 198 * {@code java.util} - valid, excludes all classes inside {@code java.util}, 199 * but not from the subpackages. 200 * </li> 201 * <li> 202 * {@code java.util.} - invalid, should not end with a dot. 203 * </li> 204 * <li> 205 * {@code java.util.*} - invalid, should not end with a star. 206 * </li> 207 * </ul> 208 * <p> 209 * Note, that checkstyle will ignore all classes from the {@code java.lang} 210 * package and its subpackages, even if the {@code java.lang} was not listed 211 * in the {@code excludedPackages} parameter. 212 * </p> 213 * <p> 214 * Also note, that {@code excludedPackages} will not exclude classes, imported 215 * via wildcard (e.g. {@code import java.math.*}). Instead of wildcard import 216 * you should use direct import (e.g. {@code import java.math.BigDecimal}). 217 * </p> 218 * <p> 219 * Also note, that checkstyle will not exclude classes within the same file 220 * even if it was listed in the {@code excludedPackages} parameter. 221 * For example, assuming the config is 222 * </p> 223 * <pre> 224 * <module name="ClassDataAbstractionCoupling"> 225 * <property name="excludedPackages" value="a.b"/> 226 * </module> 227 * </pre> 228 * <p> 229 * And the file {@code a.b.Foo.java} is: 230 * </p> 231 * <pre> 232 * package a.b; 233 * 234 * import a.b.Bar; 235 * import a.b.c.Baz; 236 * 237 * public class Foo { 238 * public Bar bar; // Will be ignored, located inside ignored a.b package 239 * public Baz baz; // Will not be ignored, located inside a.b.c package 240 * public Data data; // Will not be ignored, same file 241 * 242 * class Data { 243 * public Foo foo; // Will not be ignored, same file 244 * } 245 * } 246 * </pre> 247 * <p> 248 * The {@code bar} member will not be counted, since the {@code a.b} added 249 * to the {@code excludedPackages}. The {@code baz} member will be counted, 250 * since the {@code a.b.c} was not added to the {@code excludedPackages}. 251 * The {@code data} and {@code foo} members will be counted, as they are inside same file. 252 * </p> 253 * <p> 254 * Example of usage: 255 * </p> 256 * <pre> 257 * <module name="ClassDataAbstractionCoupling"> 258 * <property name="excludedPackages" value="java.util, java.math"/> 259 * </module> 260 * </pre> 261 * 262 * @since 3.4 263 * 264 */ 265public final class ClassDataAbstractionCouplingCheck 266 extends AbstractClassCouplingCheck { 267 268 /** 269 * A key is pointing to the warning message text in "messages.properties" 270 * file. 271 */ 272 public static final String MSG_KEY = "classDataAbstractionCoupling"; 273 274 /** Default allowed complexity. */ 275 private static final int DEFAULT_MAX = 7; 276 277 /** Creates bew instance of the check. */ 278 public ClassDataAbstractionCouplingCheck() { 279 super(DEFAULT_MAX); 280 } 281 282 @Override 283 public int[] getRequiredTokens() { 284 return new int[] { 285 TokenTypes.PACKAGE_DEF, 286 TokenTypes.IMPORT, 287 TokenTypes.CLASS_DEF, 288 TokenTypes.INTERFACE_DEF, 289 TokenTypes.ENUM_DEF, 290 TokenTypes.LITERAL_NEW, 291 }; 292 } 293 294 @Override 295 public int[] getAcceptableTokens() { 296 return getRequiredTokens(); 297 } 298 299 // -@cs[SimpleAccessorNameNotation] Overrides method from the base class. 300 // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166 301 @Override 302 protected String getLogMessageId() { 303 return MSG_KEY; 304 } 305 306}