diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/utils/ModuleReflectionUtil.java b/src/main/java/com/puppycrawl/tools/checkstyle/utils/ModuleReflectionUtil.java index baea8d1a0a6..1609b4bd657 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/utils/ModuleReflectionUtil.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/utils/ModuleReflectionUtil.java @@ -24,6 +24,7 @@ import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import com.google.common.reflect.ClassPath; @@ -41,10 +42,43 @@ */ public final class ModuleReflectionUtil { + /** Default identification predicate. */ + private static final Predicate> DEFAULT_IDENTIFICATION_PREDICATE = clazz -> { + return isCheckstyleTreeWalkerCheck(clazz) + || isFileSetModule(clazz) + || isFilterModule(clazz) + || isFileFilterModule(clazz) + || isTreeWalkerFilterModule(clazz) + || isAuditListener(clazz) + || isRootModule(clazz); + }; + + /** Current identification predicate. */ + private static Predicate> identificationPredicate = DEFAULT_IDENTIFICATION_PREDICATE; + /** Prevent instantiation. */ private ModuleReflectionUtil() { } + /** + * Allows Checkstyle to understand more modules to work with it via a + * predicate. This creates a chain of predicates for identification + * purposes. If a prior predicate fails to identify a module, it will + * continue next on the chain until all say the class cannot be identified. + * + * @param newPredicate The provided predicate that will return {@code true} + * if the class given to it is identified as a type of module, + * otherwise {@code false} if it does not. + */ + public static void addNewModuleIdentification(Predicate> newPredicate) { + identificationPredicate = newPredicate.or(identificationPredicate); + } + + /** Resets the identification process Checkstyle uses to know if a class is a module. */ + public static void resetIdentification() { + identificationPredicate = DEFAULT_IDENTIFICATION_PREDICATE; + } + /** * Gets checkstyle's modules (directly, not recursively) in the given packages. * @@ -74,13 +108,7 @@ public static Set> getCheckstyleModules( */ public static boolean isCheckstyleModule(Class clazz) { return isValidCheckstyleClass(clazz) - && (isCheckstyleTreeWalkerCheck(clazz) - || isFileSetModule(clazz) - || isFilterModule(clazz) - || isFileFilterModule(clazz) - || isTreeWalkerFilterModule(clazz) - || isAuditListener(clazz) - || isRootModule(clazz)); + && identificationPredicate.test(clazz); } /** diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/utils/ModuleReflectionUtilTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/utils/ModuleReflectionUtilTest.java index 4ab31c78e23..9a376efe833 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/utils/ModuleReflectionUtilTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/utils/ModuleReflectionUtilTest.java @@ -179,6 +179,29 @@ public void testKeepEclipseHappy() { .isEqualTo(1); } + @Test + public void testIdentification() { + assertWithMessage("Should return false when invalid class is passed by default") + .that(ModuleReflectionUtil + .isCheckstyleModule(InvalidWithDefaultConstructorClass.class)) + .isFalse(); + + ModuleReflectionUtil.addNewModuleIdentification( + clazz -> clazz == InvalidWithDefaultConstructorClass.class); + + assertWithMessage("Should return true with a new identification") + .that(ModuleReflectionUtil + .isCheckstyleModule(InvalidWithDefaultConstructorClass.class)) + .isTrue(); + + ModuleReflectionUtil.resetIdentification(); + + assertWithMessage("Should return false when identification is reset") + .that(ModuleReflectionUtil + .isCheckstyleModule(InvalidWithDefaultConstructorClass.class)) + .isFalse(); + } + private static class ValidCheckstyleClass extends AutomaticBean { // empty, use default constructor @@ -380,4 +403,12 @@ protected void finishLocalSetup() { } + private static class InvalidWithDefaultConstructorClass extends AutomaticBean { + @Override + protected void finishLocalSetup() { + // dummy method + } + + } + }