Skip to content

Commit be259d1

Browse files
committed
Updated CheckstyleAutoFix to load report
1 parent 501dedc commit be259d1

File tree

7 files changed

+218
-37
lines changed

7 files changed

+218
-37
lines changed

config/import-control.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@
1111
<allow pkg="javax.xml.stream"/>
1212
<allow pkg="org.checkstyle"/>
1313
<allow pkg="java.util"/>
14+
<allow pkg="org.reflections"/>
1415
</import-control>

pom.xml

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@
4545

4646
<dependencies>
4747

48+
<dependency>
49+
<groupId>org.reflections</groupId>
50+
<artifactId>reflections</artifactId>
51+
<version>0.10.2</version>
52+
</dependency>
53+
4854
<!-- Checkstyle dependency for parsing Checkstyle configs -->
4955
<dependency>
5056
<groupId>com.puppycrawl.tools</groupId>
@@ -111,32 +117,6 @@
111117
</configuration>
112118
</plugin>
113119

114-
<plugin>
115-
<groupId>org.openrewrite.maven</groupId>
116-
<artifactId>rewrite-maven-plugin</artifactId>
117-
<version>${rewrite.maven.plugin}</version>
118-
<configuration>
119-
<activeRecipes>
120-
<recipe>org.checkstyle.autofix.CheckstyleAutoFix</recipe>
121-
</activeRecipes>
122-
<exclusions>
123-
<exclusion>src/test/resources/**</exclusion>
124-
</exclusions>
125-
<recipeArtifactCoordinates>
126-
<coordinate>org.checkstyle.autofix:checkstyle-openrewrite-recipes:1.0.0</coordinate>
127-
</recipeArtifactCoordinates>
128-
</configuration>
129-
<executions>
130-
<execution>
131-
<id>checkstyle-autofix</id>
132-
<phase>process-sources</phase>
133-
<goals>
134-
<goal>run</goal>
135-
</goals>
136-
</execution>
137-
</executions>
138-
</plugin>
139-
140120
<!-- Checkstyle plugin for code style regulation -->
141121

142122
<plugin>
@@ -176,6 +156,33 @@
176156
</execution>
177157
</executions>
178158
</plugin>
159+
160+
<plugin>
161+
<groupId>org.openrewrite.maven</groupId>
162+
<artifactId>rewrite-maven-plugin</artifactId>
163+
<version>${rewrite.maven.plugin}</version>
164+
<configuration>
165+
<activeRecipes>
166+
<recipe>CheckstyleAutoFixConfigured</recipe>
167+
</activeRecipes>
168+
<exclusions>
169+
<exclusion>src/test/resources/**</exclusion>
170+
</exclusions>
171+
<recipeArtifactCoordinates>
172+
<coordinate>org.checkstyle.autofix:checkstyle-openrewrite-recipes:1.0.0</coordinate>
173+
</recipeArtifactCoordinates>
174+
</configuration>
175+
<executions>
176+
<execution>
177+
<id>checkstyle-autofix</id>
178+
<phase>verify</phase>
179+
<goals>
180+
<goal>run</goal>
181+
</goals>
182+
</execution>
183+
</executions>
184+
</plugin>
185+
179186
</plugins>
180187
</build>
181188

rewrite.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
type: specs.openrewrite.org/v1beta/recipe
3+
name: CheckstyleAutoFixConfigured
4+
displayName: Checkstyle Auto Fix Configured
5+
recipeList:
6+
- org.checkstyle.autofix.CheckstyleAutoFix:
7+
violationReportPath: "target/checkstyle/checkstyle-report.xml"

src/main/java/org/checkstyle/autofix/CheckstyleAutoFix.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,27 @@
1717

1818
package org.checkstyle.autofix;
1919

20-
import java.util.Collections;
20+
import java.nio.file.Path;
2121
import java.util.List;
2222

23-
import org.checkstyle.autofix.recipe.UpperEll;
23+
import org.checkstyle.autofix.parser.CheckstyleReportsParser;
24+
import org.checkstyle.autofix.parser.CheckstyleViolation;
25+
import org.openrewrite.Option;
2426
import org.openrewrite.Recipe;
2527

2628
/**
2729
* Main recipe that automatically fixes all supported Checkstyle violations.
2830
*/
29-
public class CheckstyleAutoFix extends Recipe {
31+
public final class CheckstyleAutoFix extends Recipe {
32+
33+
@Option(displayName = "ViolationReportPath",
34+
description = "Path to the Checkstyle violation report XML file.",
35+
example = "target/checkstyle-result.xml")
36+
private String violationReportPath;
37+
38+
public CheckstyleAutoFix() {
39+
this.violationReportPath = null;
40+
}
3041

3142
@Override
3243
public String getDisplayName() {
@@ -38,11 +49,16 @@ public String getDescription() {
3849
return "Automatically fixes Checkstyle violations.";
3950
}
4051

52+
public String getViolationReportPath() {
53+
return violationReportPath;
54+
}
55+
4156
@Override
4257
public List<Recipe> getRecipeList() {
43-
return Collections.singletonList(
4458

45-
new UpperEll()
46-
);
59+
final List<CheckstyleViolation> violations = CheckstyleReportsParser
60+
.parse(Path.of(violationReportPath));
61+
62+
return CheckstyleRecipeRegistry.getRecipes(violations);
4763
}
4864
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
///////////////////////////////////////////////////////////////////////////////////////////////
2+
// checkstyle-openrewrite-recipes: Automatically fix Checkstyle violations with OpenRewrite.
3+
// Copyright (C) 2025 The Checkstyle OpenRewrite Recipes Authors
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
///////////////////////////////////////////////////////////////////////////////////////////////
17+
18+
package org.checkstyle.autofix;
19+
20+
import java.util.ArrayList;
21+
import java.util.HashMap;
22+
import java.util.List;
23+
import java.util.Map;
24+
import java.util.Set;
25+
import java.util.function.Function;
26+
import java.util.stream.Collectors;
27+
28+
import org.checkstyle.autofix.parser.CheckstyleViolation;
29+
import org.openrewrite.Recipe;
30+
import org.reflections.Reflections;
31+
32+
public final class CheckstyleRecipeRegistry {
33+
34+
private static final Map<String, Function<List<CheckstyleViolation>, Recipe>> RECIPE_MAP =
35+
new HashMap<>();
36+
37+
static {
38+
39+
final List<Class<?>> recipeClasses;
40+
try {
41+
recipeClasses = getAllClassesThatExtendRecipe();
42+
}
43+
catch (ClassNotFoundException exception) {
44+
throw new IllegalStateException("Failed to load recipe classes "
45+
+ "from org.checkstyle.autofix.recipe", exception);
46+
}
47+
48+
for (Class<?> recipeClass : recipeClasses) {
49+
final String checkName = recipeClass.getSimpleName() + "Check";
50+
RECIPE_MAP.put(checkName, violations -> {
51+
try {
52+
return (Recipe) recipeClass.getConstructor(List.class).newInstance(violations);
53+
}
54+
catch (ReflectiveOperationException exception) {
55+
throw new IllegalStateException("Failed to create recipe instance: "
56+
+ recipeClass.getName());
57+
}
58+
});
59+
}
60+
}
61+
62+
private CheckstyleRecipeRegistry() {
63+
// utility class
64+
}
65+
66+
/**
67+
* Returns a list of Recipe objects based on the given list of Checkstyle violations.
68+
* The method groups violations by their check name, finds the matching recipe factory
69+
* using the simple name of the check, and applies the factory to generate Recipe instances.
70+
*
71+
* @param violations the list of Checkstyle violations
72+
* @return a list of generated Recipe objects
73+
*/
74+
public static List<Recipe> getRecipes(List<CheckstyleViolation> violations) {
75+
76+
final Map<String, List<CheckstyleViolation>> violationsByCheck = violations.stream()
77+
.collect(Collectors.groupingBy(CheckstyleViolation::getSource));
78+
79+
final List<Recipe> recipes = new ArrayList<>();
80+
81+
for (Map.Entry<String, List<CheckstyleViolation>> entry : violationsByCheck.entrySet()) {
82+
final String checkName = entry.getKey();
83+
final String simpleCheckName = checkName
84+
.substring(checkName.lastIndexOf('.') + 1);
85+
final List<CheckstyleViolation> records = entry.getValue();
86+
87+
final Function<List<CheckstyleViolation>, Recipe> recipeFactory =
88+
RECIPE_MAP.get(simpleCheckName);
89+
if (recipeFactory != null) {
90+
recipes.add(recipeFactory.apply(records));
91+
}
92+
}
93+
94+
return recipes;
95+
}
96+
97+
private static List<Class<?>> getAllClassesThatExtendRecipe() throws ClassNotFoundException {
98+
final Reflections reflections = new Reflections("org.checkstyle.autofix.recipe");
99+
final Set<Class<? extends Recipe>> recipeClasses = reflections.getSubTypesOf(Recipe.class);
100+
return new ArrayList<>(recipeClasses);
101+
}
102+
}

src/main/java/org/checkstyle/autofix/recipe/UpperEll.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
package org.checkstyle.autofix.recipe;
1919

2020
import java.nio.file.Path;
21-
import java.util.ArrayList;
2221
import java.util.List;
2322
import java.util.concurrent.CancellationException;
2423
import java.util.function.Function;
@@ -42,10 +41,6 @@ public class UpperEll extends Recipe {
4241

4342
private final List<CheckstyleViolation> violations;
4443

45-
public UpperEll() {
46-
this(new ArrayList<>());
47-
}
48-
4944
public UpperEll(List<CheckstyleViolation> violations) {
5045
this.violations = violations;
5146
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
///////////////////////////////////////////////////////////////////////////////////////////////
2+
// checkstyle-openrewrite-recipes: Automatically fix Checkstyle violations with OpenRewrite.
3+
// Copyright (C) 2025 The Checkstyle OpenRewrite Recipes Authors
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
///////////////////////////////////////////////////////////////////////////////////////////////
17+
18+
package org.checkstyle.autofix;
19+
20+
import static org.junit.jupiter.api.Assertions.assertEquals;
21+
22+
import java.util.List;
23+
24+
import org.checkstyle.autofix.parser.CheckstyleViolation;
25+
import org.junit.jupiter.api.Test;
26+
import org.openrewrite.Recipe;
27+
28+
public class CheckstyleRecipeRegistryTest {
29+
30+
@Test
31+
void testGetRecipesReturnsCorrectRecipe() {
32+
33+
final List<CheckstyleViolation> violations = List.of(
34+
new CheckstyleViolation(5, 10, "error",
35+
"com.puppycrawl.tools.checkstyle.checks.UpperEllCheck",
36+
"Use uppercase 'L' for long literals.", "Example1.java"),
37+
38+
new CheckstyleViolation(15, 20, "error",
39+
"com.puppycrawl.tools.checkstyle.checks.UpperEllCheck",
40+
"Use uppercase 'L' for long literals.", "Example2.java"),
41+
42+
new CheckstyleViolation(8, 12, "error",
43+
"com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck",
44+
"Variable should be declared final.", "Example3.java")
45+
);
46+
47+
final List<Recipe> recipes = CheckstyleRecipeRegistry.getRecipes(violations);
48+
49+
assertEquals(1, recipes.size(), "Should return one recipe");
50+
assertEquals("UpperEll recipe", recipes.get(0).getDisplayName());
51+
}
52+
53+
}

0 commit comments

Comments
 (0)