From fd84f42b9e322cc74990ebb7ed76d5deb9dd5de4 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 14 Dec 2023 12:48:31 +0000 Subject: [PATCH] Improve compatibility with Checkstyle 10 Closes gh-395 --- .../checkstyle/SpringConfigurationLoader.java | 17 +++-- .../checkstyle/check/SpringJUnit5Check.java | 74 ++++++++++++++----- 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java index 17e4e403..12bd56c7 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/SpringConfigurationLoader.java @@ -24,10 +24,11 @@ import com.puppycrawl.tools.checkstyle.ConfigurationLoader; import com.puppycrawl.tools.checkstyle.ConfigurationLoader.IgnoredModulesOptions; import com.puppycrawl.tools.checkstyle.PropertyResolver; -import com.puppycrawl.tools.checkstyle.api.AutomaticBean; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.Configurable; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.api.Context; +import com.puppycrawl.tools.checkstyle.api.Contextualizable; import com.puppycrawl.tools.checkstyle.api.FileSetCheck; import org.xml.sax.InputSource; @@ -79,9 +80,7 @@ private Object createModule(Configuration configuration) { String name = configuration.getName(); try { Object module = this.moduleFactory.createModule(name); - if (module instanceof AutomaticBean) { - initialize(configuration, (AutomaticBean) module); - } + initialize(configuration, module); return module; } catch (CheckstyleException ex) { @@ -89,9 +88,13 @@ private Object createModule(Configuration configuration) { } } - private void initialize(Configuration configuration, AutomaticBean bean) throws CheckstyleException { - bean.contextualize(this.context); - bean.configure(configuration); + private void initialize(Configuration configuration, Object module) throws CheckstyleException { + if (module instanceof Contextualizable) { + ((Contextualizable) module).contextualize(this.context); + } + if (module instanceof Configurable) { + ((Configurable) module).configure(configuration); + } } } diff --git a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java index 5b5dc191..db7cbbfd 100644 --- a/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java +++ b/spring-javaformat/spring-javaformat-checkstyle/src/main/java/io/spring/javaformat/checkstyle/check/SpringJUnit5Check.java @@ -19,12 +19,14 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; @@ -38,33 +40,33 @@ */ public class SpringJUnit5Check extends AbstractSpringCheck { - private static final String JUNIT4_TEST_ANNOTATION = "org.junit.Test"; + private static final String JUNIT4_TEST_ANNOTATION_NAME = "org.junit.Test"; - private static final List TEST_ANNOTATIONS; + private static final List TEST_ANNOTATIONS; static { - Set annotations = new LinkedHashSet<>(); - annotations.add("RepeatedTest"); - annotations.add("Test"); - annotations.add("TestFactory"); - annotations.add("TestTemplate"); - annotations.add("ParameterizedTest"); + Set annotations = new LinkedHashSet<>(); + annotations.add(new Annotation("org.junit.jupiter.api", "RepeatedTest")); + annotations.add(new Annotation("org.junit.jupiter.api", "Test")); + annotations.add(new Annotation("org.junit.jupiter.api", "TestFactory")); + annotations.add(new Annotation("org.junit.jupiter.api", "TestTemplate")); + annotations.add(new Annotation("org.junit.jupiter.api", "ParameterizedTest")); TEST_ANNOTATIONS = Collections.unmodifiableList(new ArrayList<>(annotations)); } - private static final List LIFECYCLE_ANNOTATIONS; + private static final List LIFECYCLE_ANNOTATIONS; static { - Set annotations = new LinkedHashSet<>(); - annotations.add("BeforeAll"); - annotations.add("BeforeEach"); - annotations.add("AfterAll"); - annotations.add("AfterEach"); + Set annotations = new LinkedHashSet<>(); + annotations.add(new Annotation("org.junit.jupiter.api", "BeforeAll")); + annotations.add(new Annotation("org.junit.jupiter.api", "BeforeEach")); + annotations.add(new Annotation("org.junit.jupiter.api", "AfterAll")); + annotations.add(new Annotation("org.junit.jupiter.api", "AfterEach")); LIFECYCLE_ANNOTATIONS = Collections.unmodifiableList(new ArrayList<>(annotations)); } private static final Set BANNED_IMPORTS; static { Set bannedImports = new LinkedHashSet<>(); - bannedImports.add(JUNIT4_TEST_ANNOTATION); + bannedImports.add(JUNIT4_TEST_ANNOTATION_NAME); bannedImports.add("org.junit.After"); bannedImports.add("org.junit.AfterClass"); bannedImports.add("org.junit.Before"); @@ -106,14 +108,33 @@ public void visitToken(DetailAST ast) { } private void visitMethodDef(DetailAST ast) { - if (AnnotationUtil.containsAnnotation(ast, TEST_ANNOTATIONS)) { + if (containsAnnotation(ast, TEST_ANNOTATIONS)) { this.testMethods.add(ast); } - if (AnnotationUtil.containsAnnotation(ast, LIFECYCLE_ANNOTATIONS)) { + if (containsAnnotation(ast, LIFECYCLE_ANNOTATIONS)) { this.lifecycleMethods.add(ast); } } + private boolean containsAnnotation(DetailAST ast, List annotations) { + List annotationNames = annotations.stream().flatMap((annotation) -> + Stream.of(annotation.simpleName, annotation.fullyQualifiedName())).collect(Collectors.toList()); + try { + return AnnotationUtil.containsAnnotation(ast, annotationNames); + } + catch (NoSuchMethodError ex) { + // Checkstyle >= 10.3 (https://github.com/checkstyle/checkstyle/issues/14134) + Set annotationNamesSet = new HashSet<>(annotationNames); + try { + return (boolean) AnnotationUtil.class.getMethod("containsAnnotation", DetailAST.class, Set.class) + .invoke(null, ast, annotationNamesSet); + } + catch (Exception ex2) { + throw new RuntimeException("containsAnnotation failed", ex2); + } + } + } + private void visitImport(DetailAST ast) { FullIdent ident = FullIdent.createFullIdentBelow(ast); this.imports.put(ident.getText(), ident); @@ -146,7 +167,7 @@ private void check() { } } for (DetailAST testMethod : this.testMethods) { - if (AnnotationUtil.containsAnnotation(testMethod, JUNIT4_TEST_ANNOTATION)) { + if (AnnotationUtil.containsAnnotation(testMethod, JUNIT4_TEST_ANNOTATION_NAME)) { log(testMethod, "junit5.bannedTestAnnotation"); } } @@ -176,4 +197,21 @@ public void setUnlessImports(String unlessImports) { .unmodifiableList(Arrays.stream(unlessImports.split(",")).map(String::trim).collect(Collectors.toList())); } + private static final class Annotation { + + private final String packageName; + + private final String simpleName; + + private Annotation(String packageName, String simpleName) { + this.packageName = packageName; + this.simpleName = simpleName; + } + + private String fullyQualifiedName() { + return this.packageName + "." + this.simpleName; + } + + } + }