LintingRulesFinder.java
package org.thewonderlemming.c4plantuml.mojo.linting;
import java.lang.reflect.Modifier;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.thewonderlemming.c4plantuml.linter.rules.AbstractLintingRule;
import org.thewonderlemming.c4plantuml.mojo.linting.rules.custom.AbstractCustomLintingRule;
import org.thewonderlemming.c4plantuml.mojo.linting.rules.custom.AbstractCustomLintingRuleFactory;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import io.github.classgraph.ScanResult;
/**
* An utility class to detect and return {@link AbstractLintingRule} and {@link AbstractCustomLintingRule} within the
* classpath, including the shipped dependencies.
*
* @author thewonderlemming
*
*/
public class LintingRulesFinder {
private static final Logger LOGGER = LoggerFactory.getLogger(LintingRulesFinder.class);
/**
* Finds and returns every non-abstract child class of {@link AbstractLintingRule} in the classpath, including
* within the dependencies.
*
* @return a set of the found {@link AbstractLintingRule} classes.
*/
@SuppressWarnings("unchecked")
public static Set<Class<? extends AbstractLintingRule>> findBuiltInLintingRules() {
try (final ScanResult scanResult = new ClassGraph().enableClassInfo().ignoreClassVisibility().scan()) {
return scanResult
.getSubclasses(AbstractLintingRule.class.getName())
.stream()
.map(ClassInfo::getName)
.map(LintingRulesFinder::getClassForName)
.filter(Optional::isPresent)
.map(Optional::get)
.map(clazz -> (Class<? extends AbstractLintingRule>) clazz)
.filter(LintingRulesFinder::isNotAbstract)
.collect(Collectors.toSet());
}
}
/**
* Finds and returns every non-abstract child class of {@link AbstractCustomLintingRule} in the classpath, including
* within the dependencies.
*
* @return a set of the found {@link AbstractCustomLintingRule} classes.
*/
@SuppressWarnings("unchecked")
public static Set<Class<? extends AbstractCustomLintingRuleFactory<?>>> findCustomLintingRuleFactories() {
try (final ScanResult scanResult = new ClassGraph().enableClassInfo().ignoreClassVisibility().scan()) {
return scanResult
.getSubclasses(AbstractCustomLintingRuleFactory.class.getName())
.stream()
.map(ClassInfo::getName)
.map(LintingRulesFinder::getClassForName)
.filter(Optional::isPresent)
.map(Optional::get)
.map(clazz -> (Class<? extends AbstractCustomLintingRuleFactory<?>>) clazz)
.filter(LintingRulesFinder::isNotAbstract)
.collect(Collectors.toSet());
}
}
private static Optional<Class<?>> getClassForName(final String className) {
try {
return Optional.ofNullable(Class.forName(className));
} catch (final ClassNotFoundException e) {
LOGGER.error("Error while scanning classpath to detect linting rules: {}", e.getMessage());
}
return Optional.empty();
}
private static boolean isNotAbstract(final Class<?> clazz) {
return !Modifier.isAbstract(clazz.getModifiers());
}
private LintingRulesFinder() {
}
}