+ * Property {@code ignoreAnnotatedBy} - Ignore classes annotated
+ * with the specified annotation(s). Name in this property must
+ * be an exact match for the annotation name on the class. If target
+ * class has annotation in fully qualified name (with package), this
+ * property should have such name too. If target class has annotation
+ * in simple name, this property needs to have the same simple name.
+ * Type is {@code java.lang.String[]}.
+ * Default value is {@code ""}.
+ *
+ *
*
* Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
*
@@ -74,6 +90,15 @@ public class HideUtilityClassConstructorCheck extends AbstractCheck {
*/
public static final String MSG_KEY = "hide.utility.class";
+ /**
+ * Ignore classes annotated with the specified annotation(s). Name in
+ * this property must be an exact match for the annotation name on the class.
+ * If target class has annotation in fully qualified name (with package), this
+ * property should have such name too. If target class has annotation in simple
+ * name, this property needs to have the same simple name.
+ */
+ private Set ignoreAnnotatedBy = Collections.emptySet();
+
@Override
public int[] getDefaultTokens() {
return getRequiredTokens();
@@ -92,7 +117,7 @@ public int[] getRequiredTokens() {
@Override
public void visitToken(DetailAST ast) {
// abstract class could not have private constructor
- if (!isAbstract(ast)) {
+ if (!isAbstract(ast) && !shouldIgnoreClass(ast)) {
final boolean hasStaticModifier = isStatic(ast);
final Details details = new Details(ast);
@@ -142,6 +167,30 @@ private static boolean isStatic(DetailAST ast) {
.findFirstToken(TokenTypes.LITERAL_STATIC) != null;
}
+ /**
+ * Setter to ignore classes annotated with the specified annotation(s).
+ * Name in this property must be an exact match for the annotation name on the class.
+ * If target class has annotation in fully qualified name (with package),
+ * this property should have such name too. If target class has annotation
+ * in simple name, this property needs to have the same simple name.
+ *
+ * @param annotationNames specified annotation(s)
+ * @since 10.15.0
+ */
+ public void setIgnoreAnnotatedBy(String... annotationNames) {
+ ignoreAnnotatedBy = Set.of(annotationNames);
+ }
+
+ /**
+ * Checks if class is annotated by specific annotation(s) to skip.
+ *
+ * @param ast class to check
+ * @return true if annotated by ignored annotations
+ */
+ private boolean shouldIgnoreClass(DetailAST ast) {
+ return AnnotationUtil.containsAnnotation(ast, ignoreAnnotatedBy);
+ }
+
/**
* Details of class that are required for validation.
*/
diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/design/HideUtilityClassConstructorCheck.xml b/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/design/HideUtilityClassConstructorCheck.xml
index 897b5c51760..17db64738ec 100644
--- a/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/design/HideUtilityClassConstructorCheck.xml
+++ b/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/design/HideUtilityClassConstructorCheck.xml
@@ -30,6 +30,16 @@
}
}
</pre>
+
+
+ Ignore classes annotated
+ with the specified annotation(s). Name in this property must
+ be an exact match for the annotation name on the class. If target
+ class has annotation in fully qualified name (with package), this
+ property should have such name too. If target class has annotation
+ in simple name, this property needs to have the same simple name.
+
+
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckTest.java
index 347c5ba6a3a..7e6d4c32102 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckTest.java
@@ -146,4 +146,26 @@ public void testGetAcceptableTokens() {
.isEqualTo(expected);
}
+ @Test
+ public void testIgnoreAnnotatedBy() throws Exception {
+ final String[] expected = {
+ "30:1: " + getCheckMessage(MSG_KEY),
+ };
+ verifyWithInlineConfigParser(
+ getPath("InputHideUtilityClassConstructorIgnoreAnnotationBy.java"),
+ expected
+ );
+ }
+
+ @Test
+ public void testIgnoreAnnotatedByFullQualifier() throws Exception {
+ final String[] expected = {
+ "9:1: " + getCheckMessage(MSG_KEY),
+ };
+ verifyWithInlineConfigParser(
+ getPath("InputHideUtilityClassConstructor"
+ + "IgnoreAnnotationByFullyQualifiedName.java"),
+ expected
+ );
+ }
}
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/InputHideUtilityClassConstructorIgnoreAnnotationBy.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/InputHideUtilityClassConstructorIgnoreAnnotationBy.java
new file mode 100644
index 00000000000..3af48f65fc0
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/InputHideUtilityClassConstructorIgnoreAnnotationBy.java
@@ -0,0 +1,46 @@
+/*
+HideUtilityClassConstructor
+ignoreAnnotatedBy = Skip, SkipWithParam, SkipWithAnnotationAsParam
+
+*/
+
+package com.puppycrawl.tools.checkstyle.checks.design.hideutilityclassconstructor;
+
+@Skip
+public class InputHideUtilityClassConstructorIgnoreAnnotationBy {
+ public static void func() {}
+}
+
+@SkipWithParam(name = "tool1")
+class ToolClass1 {
+ public static void func() {}
+}
+
+@SkipWithAnnotationAsParam(skip = @Skip)
+class ToolClass2 {
+ public static void func() {}
+}
+
+@CommonAnnot
+@Skip
+class ToolClass3 {
+ public static void func() {}
+}
+
+@CommonAnnot // violation
+class ToolClass4 {
+ public static void func() {}
+}
+
+
+@interface Skip {}
+
+@interface SkipWithParam {
+ String name();
+}
+
+@interface SkipWithAnnotationAsParam {
+ Skip skip();
+}
+
+@interface CommonAnnot {}
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/InputHideUtilityClassConstructorIgnoreAnnotationByFullyQualifiedName.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/InputHideUtilityClassConstructorIgnoreAnnotationByFullyQualifiedName.java
new file mode 100644
index 00000000000..b01b3cdfff2
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/InputHideUtilityClassConstructorIgnoreAnnotationByFullyQualifiedName.java
@@ -0,0 +1,19 @@
+/*
+HideUtilityClassConstructor
+ignoreAnnotatedBy = java.lang.Deprecated
+
+*/
+
+package com.puppycrawl.tools.checkstyle.checks.design.hideutilityclassconstructor;
+
+@Deprecated // violation
+public class InputHideUtilityClassConstructorIgnoreAnnotationByFullyQualifiedName {
+ public static void func() {}
+}
+
+@java.lang.Deprecated
+class DeprecatedClass {
+ public static void func() {}
+}
+
+@interface Deprecated {}
diff --git a/src/xdocs-examples/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckExamplesTest.java b/src/xdocs-examples/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckExamplesTest.java
index 2537e6182b6..648f7062ff9 100644
--- a/src/xdocs-examples/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckExamplesTest.java
+++ b/src/xdocs-examples/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheckExamplesTest.java
@@ -36,9 +36,16 @@ protected String getPackageLocation() {
public void testExample1() throws Exception {
final String[] expected = {
"12:1: " + getCheckMessage(MSG_KEY),
- "37:1: " + getCheckMessage(MSG_KEY),
+ "38:1: " + getCheckMessage(MSG_KEY),
};
verifyWithInlineConfigParser(getPath("Example1.java"), expected);
}
+
+ @Test
+ public void testExample2() throws Exception {
+ final String[] expected = {};
+
+ verifyWithInlineConfigParser(getPath("Example2.java"), expected);
+ }
}
diff --git a/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/Example1.java b/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/Example1.java
index 0af95eb74bb..102c2e0ffd3 100644
--- a/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/Example1.java
+++ b/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/Example1.java
@@ -9,7 +9,8 @@
package com.puppycrawl.tools.checkstyle.checks.design.hideutilityclassconstructor;
// xdoc section -- start
-class Example1 { // violation
+@java.lang.Deprecated // violation
+class Example1 {
public Example1() {
}
@@ -18,23 +19,24 @@ public static void fun() {
}
}
-class Foo { // OK
+class Foo1 {
- private Foo() {
+ private Foo1() {
}
static int n;
}
-class Bar { // OK
+class Bar1 {
- protected Bar() {
+ protected Bar1() {
// prevents calls from subclass
throw new UnsupportedOperationException();
}
}
-class UtilityClass { // violation
+@SpringBootApplication // violation
+class ApplicationClass1 {
static float f;
}
diff --git a/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/Example2.java b/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/Example2.java
new file mode 100644
index 00000000000..cea07636b07
--- /dev/null
+++ b/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/Example2.java
@@ -0,0 +1,47 @@
+/*xml
+
+
+
+
+
+
+
+*/
+
+package com.puppycrawl.tools.checkstyle.checks.design.hideutilityclassconstructor;
+
+// xdoc section -- start
+@java.lang.Deprecated
+class Example2 { // OK, skipped by annotation
+
+ public Example2() {
+ }
+
+ public static void fun() {
+ }
+}
+
+class Foo2 {
+
+ private Foo2() {
+ }
+
+ static int n;
+}
+
+class Bar2 {
+
+ protected Bar2() {
+ // prevents calls from subclass
+ throw new UnsupportedOperationException();
+ }
+}
+
+@SpringBootApplication
+class ApplicationClass2 { // OK, skipped by annotation
+
+ static float f;
+}
+// xdoc section -- end
+@interface SpringBootApplication {}
diff --git a/src/xdocs/checks/design/hideutilityclassconstructor.xml b/src/xdocs/checks/design/hideutilityclassconstructor.xml
index cfe453eee81..5bbc561ead2 100644
--- a/src/xdocs/checks/design/hideutilityclassconstructor.xml
+++ b/src/xdocs/checks/design/hideutilityclassconstructor.xml
@@ -42,6 +42,27 @@ public class StringUtils // not final to allow subclassing
+
+
+
+
+
name
+
description
+
type
+
default value
+
since
+
+
+
ignoreAnnotatedBy
+
Ignore classes annotated with the specified annotation(s). Name in this property must be an exact match for the annotation name on the class. If target class has annotation in fully qualified name (with package), this property should have such name too. If target class has annotation in simple name, this property needs to have the same simple name.
To configure the check:
@@ -55,7 +76,8 @@ public class StringUtils // not final to allow subclassing
Example:
+
+
+ To configure the check:
+
+
+
Example:
+
+
+
+
+
+
+
+
+
To configure the check:
@@ -57,6 +66,21 @@ public class StringUtils // not final to allow subclassing
value="resources/com/puppycrawl/tools/checkstyle/checks/design/hideutilityclassconstructor/Example1.java"/>
+
+