Skip to content

Commit 76f932b

Browse files
Anmol202005timurt
authored andcommitted
Implemented report and config parser
1 parent 4c0fe1d commit 76f932b

File tree

10 files changed

+343
-2
lines changed

10 files changed

+343
-2
lines changed

config/import-control-test.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@
88
<allow pkg="org.openrewrite"/>
99
<allow pkg="org.checkstyle"/>
1010
<allow pkg="java.io"/>
11+
<allow pkg="java.util"/>
1112
<allow pkg="java.nio"/>
13+
<allow pkg="java.lang"/>
1214
</import-control>

config/import-control.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<allow pkg="org.openrewrite.java"/>
99
<allow pkg="org.openrewrite.java.tree"/>
1010
<allow pkg="java"/>
11+
<allow pkg="javax.xml.stream"/>
1112
<allow pkg="org.checkstyle"/>
1213
<allow pkg="java.util"/>
13-
</import-control>
14+
</import-control>

config/suppressions.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,8 @@
44
"-//Checkstyle//DTD SuppressionFilter Configuration 1.1//EN"
55
"https://checkstyle.org/dtds/suppressions_1_1.dtd">
66

7-
<suppressions/>
7+
<suppressions>
8+
<suppress checks="MissingJavadocType" files=".*"/>
9+
<suppress checks="JavadocVariable" files=".*"/>
10+
<suppress checks="MissingJavadocMethod" files=".*"/>
11+
</suppressions>

pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@
4444
</dependencyManagement>
4545

4646
<dependencies>
47+
48+
<!-- Checkstyle dependency for parsing Checkstyle configs -->
49+
<dependency>
50+
<groupId>com.puppycrawl.tools</groupId>
51+
<artifactId>checkstyle</artifactId>
52+
<version>${checkstyle.version}</version>
53+
</dependency>
54+
4755
<!-- OpenRewrite core dependencies - using consistent versions -->
4856
<dependency>
4957
<groupId>org.openrewrite</groupId>
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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.parser;
19+
20+
import java.io.FileInputStream;
21+
import java.io.IOException;
22+
import java.io.InputStream;
23+
import java.nio.file.Path;
24+
import java.util.ArrayList;
25+
import java.util.Iterator;
26+
import java.util.List;
27+
import java.util.Objects;
28+
29+
import javax.xml.stream.XMLEventReader;
30+
import javax.xml.stream.XMLInputFactory;
31+
import javax.xml.stream.XMLStreamException;
32+
import javax.xml.stream.events.Attribute;
33+
import javax.xml.stream.events.StartElement;
34+
import javax.xml.stream.events.XMLEvent;
35+
36+
public final class CheckstyleReportsParser {
37+
38+
private static final String FILE_TAG = "file";
39+
40+
private static final String ERROR_TAG = "error";
41+
42+
private static final String FILENAME_ATTR = "name";
43+
44+
private static final String LINE_ATTR = "line";
45+
46+
private static final String COLUMN_ATTR = "column";
47+
48+
private static final String SEVERITY_ATTR = "severity";
49+
50+
private static final String MESSAGE_ATTR = "message";
51+
52+
private static final String SOURCE_ATTR = "source";
53+
54+
private CheckstyleReportsParser() {
55+
56+
}
57+
58+
public static List<CheckstyleViolation> parse(Path xmlPath)
59+
throws IOException, XMLStreamException {
60+
61+
final List<CheckstyleViolation> result = new ArrayList<>();
62+
63+
try (InputStream inputStream = new FileInputStream(xmlPath.toFile())) {
64+
65+
final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
66+
final XMLEventReader reader = inputFactory.createXMLEventReader(inputStream);
67+
68+
try {
69+
String filename = null;
70+
71+
while (reader.hasNext()) {
72+
final XMLEvent event = reader.nextEvent();
73+
if (event.isStartElement()) {
74+
final StartElement startElement = event.asStartElement();
75+
final String startElementName = startElement.getName().getLocalPart();
76+
77+
if (FILE_TAG.equals(startElementName)) {
78+
filename = parseFileTag(startElement);
79+
}
80+
else if (ERROR_TAG.equals(startElementName)) {
81+
Objects.requireNonNull(filename, "File name can not be null");
82+
result.add(parseErrorTag(startElement, filename));
83+
}
84+
}
85+
}
86+
}
87+
finally {
88+
if (reader != null) {
89+
reader.close();
90+
}
91+
}
92+
}
93+
94+
return result;
95+
}
96+
97+
private static String parseFileTag(StartElement startElement) {
98+
String fileName = null;
99+
final Iterator<Attribute> attributes = startElement.getAttributes();
100+
while (attributes.hasNext()) {
101+
final Attribute attribute = attributes.next();
102+
if (FILENAME_ATTR.equals(attribute.getName().getLocalPart())) {
103+
fileName = attribute.getValue();
104+
break;
105+
}
106+
}
107+
return fileName;
108+
}
109+
110+
private static CheckstyleViolation parseErrorTag(StartElement startElement, String filename) {
111+
Integer line = null;
112+
Integer column = null;
113+
String source = null;
114+
String message = null;
115+
String severity = null;
116+
final Iterator<Attribute> attributes = startElement
117+
.getAttributes();
118+
while (attributes.hasNext()) {
119+
final Attribute attribute = attributes.next();
120+
final String attrName = attribute.getName().getLocalPart();
121+
switch (attrName) {
122+
case LINE_ATTR:
123+
line = Integer.valueOf(attribute.getValue());
124+
break;
125+
case COLUMN_ATTR:
126+
column = Integer.parseInt(attribute.getValue());
127+
break;
128+
case SEVERITY_ATTR:
129+
severity = attribute.getValue();
130+
break;
131+
case MESSAGE_ATTR:
132+
message = attribute.getValue();
133+
break;
134+
case SOURCE_ATTR:
135+
source = attribute.getValue();
136+
break;
137+
default:
138+
break;
139+
}
140+
}
141+
return new CheckstyleViolation(
142+
line, column, severity, source, message, filename);
143+
144+
}
145+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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.parser;
19+
20+
public final class CheckstyleViolation {
21+
22+
private final Integer line;
23+
24+
private final Integer column;
25+
26+
private final String severity;
27+
28+
private final String source;
29+
30+
private final String message;
31+
32+
private final String fileName;
33+
34+
public CheckstyleViolation(Integer line, Integer column,
35+
String severity, String source, String message, String fileName) {
36+
this.line = line;
37+
this.column = column;
38+
this.severity = severity;
39+
this.source = source;
40+
this.message = message;
41+
this.fileName = fileName;
42+
}
43+
44+
public int getLine() {
45+
return line;
46+
}
47+
48+
public int getColumn() {
49+
return column;
50+
}
51+
52+
public String getSource() {
53+
return source;
54+
}
55+
56+
public String getMessage() {
57+
return message;
58+
}
59+
60+
public String getFileName() {
61+
return fileName;
62+
}
63+
64+
public String getSeverity() {
65+
return severity;
66+
}
67+
68+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
/**
19+
* Provides classes to parse Checkstyle XML report files.
20+
*/
21+
package org.checkstyle.autofix.parser;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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.parser;
19+
20+
import static org.junit.jupiter.api.Assertions.assertEquals;
21+
import static org.junit.jupiter.api.Assertions.assertNotNull;
22+
23+
import java.nio.file.Path;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.stream.Collectors;
27+
28+
import org.junit.jupiter.api.Test;
29+
30+
public class CheckstyleReportsParserTest {
31+
32+
private static String getPath(String path) {
33+
return "src/test/resources/org/checkstyle/autofix/parser/" + path;
34+
}
35+
36+
@Test
37+
public void testParseFromResource() throws Exception {
38+
final Path xmlPath = Path.of(getPath("checkstyle-report.xml"));
39+
final List<CheckstyleViolation> records = CheckstyleReportsParser.parse(xmlPath);
40+
41+
assertNotNull(records);
42+
assertEquals(1, records.size());
43+
44+
final CheckstyleViolation record = records.get(0);
45+
assertEquals(42, record.getLine());
46+
assertEquals(13, record.getColumn());
47+
assertEquals("error", record.getSeverity());
48+
assertEquals("Example message", record.getMessage());
49+
assertEquals("com.puppycrawl.example.Check", record.getSource());
50+
assertEquals("Example.java", record.getFileName());
51+
}
52+
53+
@Test
54+
public void testParseMultipleFilesReport() throws Exception {
55+
final Path xmlPath = Path.of(getPath("checkstyle-multiple-files.xml"));
56+
final List<CheckstyleViolation> records = CheckstyleReportsParser.parse(xmlPath);
57+
58+
assertNotNull(records);
59+
assertEquals(3, records.size());
60+
61+
final Map<String, List<CheckstyleViolation>> grouped = records.stream()
62+
.collect(Collectors.groupingBy(CheckstyleViolation::getFileName));
63+
64+
assertEquals(2, grouped.size());
65+
66+
assertEquals(2, grouped.get("Main.java").size());
67+
assertEquals(1, grouped.get("Utils.java").size());
68+
69+
CheckstyleViolation record = grouped.get("Main.java").get(0);
70+
assertEquals("error", record.getSeverity());
71+
72+
record = grouped.get("Utils.java").get(0);
73+
assertEquals("warning", record.getSeverity());
74+
}
75+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<checkstyle>
2+
<file name="Main.java">
3+
<error line="10" column="5" severity="error" message="Missing javadoc" source="com.puppycrawl.Check"/>
4+
<error line="20" column="2" severity="error" message="Indentation" source="com.puppycrawl.Indent"/>
5+
</file>
6+
<file name="Utils.java">
7+
<error line="15" column="1" severity="warning" message="Unused import" source="com.puppycrawl.Import"/>
8+
</file>
9+
</checkstyle>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<checkstyle version="8.0">
3+
<file name="Example.java">
4+
<error line="42" column="13" severity="error"
5+
message="Example message"
6+
source="com.puppycrawl.example.Check"/>
7+
</file>
8+
</checkstyle>

0 commit comments

Comments
 (0)