View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.pmd.rules;
6   
7   import net.sourceforge.pmd.lang.java.ast.ASTClassDeclaration;
8   import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
9   import net.sourceforge.pmd.lang.java.ast.JModifier;
10  import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
11  
12  /**
13   * Rule to check that a class does not declare too many fields. Like the PMD
14   * built-in {@code TooManyFields} rule, this implementation counts the
15   * fields declared in the body of the class, skipping the static and the
16   * final ones, since those are constants rather than state, and reports a
17   * class that declares more than fifteen of them. Unlike the built-in
18   * rule, it skips a class that extends
19   * {@code org.apache.maven.plugin.AbstractMojo}: a Maven Mojo declares one
20   * field per {@code @Parameter} it exposes to users of the plugin goal,
21   * because the Maven Plugin API requires each configurable parameter as a
22   * directly annotated field on the Mojo, so that count tracks the number of
23   * options the goal accepts rather than the cohesion of the class.
24   * Skipping them here instead of through a
25   * {@code violationSuppressXPath} keeps a redundant
26   * {@code @SuppressWarnings("PMD.TooManyFields")} visible to
27   * {@code UnnecessaryWarningSuppression}, which PMD credits to the
28   * annotation whenever the annotation suppressor runs first.
29   *
30   * @since 1.0
31   */
32  public final class TooManyFieldsRule extends AbstractJavaRulechainRule {
33  
34      /**
35       * The base class of every Maven Mojo.
36       */
37      private static final NamedSupertype MOJO = new NamedSupertype(
38          "org.apache.maven.plugin.AbstractMojo"
39      );
40  
41      /**
42       * Default constructor.
43       */
44      public TooManyFieldsRule() {
45          super(ASTClassDeclaration.class);
46      }
47  
48      @Override
49      public Object visit(final ASTClassDeclaration type, final Object data) {
50          if (!TooManyFieldsRule.MOJO.matches(type.getSuperClassTypeNode())
51              && TooManyFieldsRule.state(type) > 15) {
52              this.asCtx(data).addViolation(type);
53          }
54          return data;
55      }
56  
57      private static long state(final ASTClassDeclaration type) {
58          return type.getDeclarations(ASTFieldDeclaration.class)
59              .filter(TooManyFieldsRule::mutable)
60              .count();
61      }
62  
63      private static boolean mutable(final ASTFieldDeclaration field) {
64          return !field.hasModifiers(JModifier.FINAL)
65              && !field.hasModifiers(JModifier.STATIC);
66      }
67  }