Skip to content

Commit c770823

Browse files
committed
Implemented report and config parser
1 parent 9d73475 commit c770823

File tree

8 files changed

+408
-0
lines changed

8 files changed

+408
-0
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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
<allow pkg="org.openrewrite.java"/>
99
<allow pkg="org.openrewrite.java.tree"/>
1010
<allow pkg="java"/>
11+
<allow pkg="javax.xml.stream"/>
12+
<allow pkg="org.thymeleaf.util"/>
1113
<allow pkg="org.checkstyle"/>
1214
<allow pkg="java.util"/>
1315
</import-control>

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: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package org.checkstyle.autofix.data;
2+
3+
/**
4+
* POJO, maps into single "error" tag of the XML.
5+
*/
6+
public final class CheckstyleRecord {
7+
8+
/**
9+
* Record line index.
10+
*/
11+
private final int line;
12+
13+
/**
14+
* Record column index.
15+
*/
16+
private final int column;
17+
18+
/**
19+
* Severity of this record.
20+
*/
21+
private final String severity;
22+
23+
/**
24+
* Name of the check that generated this record.
25+
*/
26+
private final String source;
27+
28+
/**
29+
* The message.
30+
*/
31+
private final String message;
32+
33+
/**
34+
* The xref.
35+
*/
36+
private String xref;
37+
38+
/**
39+
* POJO ctor.
40+
*
41+
* @param line
42+
* line number.
43+
* @param column
44+
* column number.
45+
* @param severity
46+
* record severity level.
47+
* @param source
48+
* name of check that generated record.
49+
* @param xref
50+
* external file reference.
51+
* @param message
52+
* error message.
53+
*/
54+
public CheckstyleRecord(int line, int column,
55+
String severity, String source, String message, String xref) {
56+
this.line = line;
57+
this.column = column;
58+
this.severity = severity;
59+
this.source = source;
60+
this.message = message;
61+
this.xref = xref;
62+
}
63+
64+
/**
65+
* Returns the line index.
66+
*
67+
* @return the line index
68+
*/
69+
public int getLine() {
70+
return line;
71+
}
72+
73+
/**
74+
* Returns the column index.
75+
*
76+
* @return the column index
77+
*/
78+
public int getColumn() {
79+
return column;
80+
}
81+
82+
/**
83+
* Returns the name of the check that generated this record.
84+
*
85+
* @return the name of the check
86+
*/
87+
public String getSource() {
88+
return source;
89+
}
90+
91+
/**
92+
* Returns the message.
93+
*
94+
* @return the message
95+
*/
96+
public String getMessage() {
97+
return message;
98+
}
99+
100+
/**
101+
* Returns the record xref.
102+
*
103+
* @return the record xref
104+
*/
105+
public String getXref() {
106+
return xref;
107+
}
108+
109+
/**
110+
* Returns the record severity.
111+
*
112+
* @return the record severity
113+
*/
114+
public String getSeverity() {
115+
return severity;
116+
}
117+
118+
}
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
package org.checkstyle.autofix.parser;
2+
3+
import java.io.FileInputStream;
4+
import java.io.FileNotFoundException;
5+
import java.io.InputStream;
6+
import java.nio.file.Path;
7+
import java.util.ArrayList;
8+
import java.util.Iterator;
9+
import java.util.List;
10+
11+
import javax.xml.stream.XMLEventReader;
12+
import javax.xml.stream.XMLInputFactory;
13+
import javax.xml.stream.XMLStreamException;
14+
import javax.xml.stream.events.Attribute;
15+
import javax.xml.stream.events.StartElement;
16+
import javax.xml.stream.events.XMLEvent;
17+
18+
import org.checkstyle.autofix.data.CheckstyleRecord;
19+
20+
/**
21+
* Contains logics of the StaX parser for the checkstyle xml reports.
22+
* If its scheme is changed, this class should be the first one to fix.
23+
*
24+
*/
25+
public final class CheckstyleReportsParser {
26+
27+
/**
28+
* String value for "file" tag.
29+
*/
30+
private static final String FILE_TAG = "file";
31+
32+
/**
33+
* String value for "error" tag.
34+
*/
35+
private static final String ERROR_TAG = "error";
36+
37+
/**
38+
* String value for "name" attribute.
39+
*/
40+
private static final String FILENAME_ATTR = "name";
41+
42+
/**
43+
* String value for "line" attribute.
44+
*/
45+
private static final String LINE_ATTR = "line";
46+
47+
/**
48+
* String value for "column" attribute.
49+
*/
50+
private static final String COLUMN_ATTR = "column";
51+
52+
/**
53+
* String value for "severity" attribute.
54+
*/
55+
private static final String SEVERITY_ATTR = "severity";
56+
57+
/**
58+
* String value for "message" attribute.
59+
*/
60+
private static final String MESSAGE_ATTR = "message";
61+
62+
/**
63+
* String value for "source" attribute.
64+
*/
65+
private static final String SOURCE_ATTR = "source";
66+
67+
/**
68+
* Private ctor, see parse method.
69+
*/
70+
private CheckstyleReportsParser() {
71+
72+
}
73+
74+
/**
75+
* Parses input XML files: creates 2 parsers
76+
* which process their XML files in rotation and try
77+
* to write their results to the ParsedContent class
78+
* inner map, where they are eagerly compared.
79+
*
80+
* @param xmlPath
81+
* path to patch XML file.
82+
* @return parsed content.
83+
* @throws FileNotFoundException
84+
* if files not found.
85+
* @throws XMLStreamException
86+
* on internal parser error.
87+
*/
88+
public static List<CheckstyleRecord> parse(Path xmlPath)
89+
throws FileNotFoundException, XMLStreamException {
90+
91+
final List<CheckstyleRecord> allRecords = new ArrayList<>();
92+
final XMLEventReader reader = createReader(xmlPath);
93+
while (reader.hasNext()) {
94+
parseXmlPortion(allRecords, reader);
95+
}
96+
return allRecords;
97+
}
98+
99+
/**
100+
* Parses portion of the XML report.
101+
*
102+
* @param allRecords
103+
* List for parsed data.
104+
* @param reader
105+
* StAX parser interface.
106+
* @throws XMLStreamException
107+
* on internal parser error.
108+
*/
109+
private static void parseXmlPortion(List<CheckstyleRecord> allRecords,
110+
XMLEventReader reader)
111+
throws XMLStreamException {
112+
113+
String filename = null;
114+
115+
while (reader.hasNext()) {
116+
final XMLEvent event = reader.nextEvent();
117+
if (event.isStartElement()) {
118+
final StartElement startElement = event.asStartElement();
119+
final String startElementName = startElement.getName()
120+
.getLocalPart();
121+
122+
if (startElementName.equals(FILE_TAG)) {
123+
final Iterator<Attribute> attributes = startElement.getAttributes();
124+
while (attributes.hasNext()) {
125+
final Attribute attribute = attributes.next();
126+
if (attribute.getName().toString().equals(FILENAME_ATTR)) {
127+
filename = attribute.getValue();
128+
}
129+
}
130+
}
131+
else if (startElementName.equals(ERROR_TAG)) {
132+
allRecords.add(parseErrorTag(startElement, filename));
133+
}
134+
}
135+
}
136+
}
137+
138+
/**
139+
* Parses "error" XML tag.
140+
*
141+
* @param startElement
142+
* cursor of StAX parser pointed on the tag.
143+
* @param filename
144+
* file name.
145+
* @return parsed data as CheckstyleRecord instance.
146+
*/
147+
private static CheckstyleRecord parseErrorTag(StartElement startElement, String filename) {
148+
int line = -1;
149+
int column = -1;
150+
String source = null;
151+
String message = null;
152+
String severity = null;
153+
final Iterator<Attribute> attributes = startElement
154+
.getAttributes();
155+
while (attributes.hasNext()) {
156+
final Attribute attribute = attributes.next();
157+
final String attrName = attribute.getName().toString();
158+
switch (attrName) {
159+
case LINE_ATTR:
160+
line = Integer.parseInt(attribute.getValue());
161+
break;
162+
case COLUMN_ATTR:
163+
column = Integer.parseInt(attribute.getValue());
164+
break;
165+
case SEVERITY_ATTR:
166+
severity = attribute.getValue();
167+
break;
168+
case MESSAGE_ATTR:
169+
message = attribute.getValue();
170+
break;
171+
case SOURCE_ATTR:
172+
source = attribute.getValue();
173+
break;
174+
default:
175+
break;
176+
}
177+
}
178+
return new CheckstyleRecord(
179+
line, column, severity, source, message, filename);
180+
181+
}
182+
183+
/**
184+
* Creates parser linked to the existing XML file.
185+
*
186+
* @param xmlFilename
187+
* name of an XML report file.
188+
* @return StAX parser interface.
189+
* @throws FileNotFoundException
190+
* on wrong filename.
191+
* @throws XMLStreamException
192+
* on internal factory failure.
193+
*/
194+
public static XMLEventReader createReader(Path xmlFilename)
195+
throws FileNotFoundException, XMLStreamException {
196+
197+
final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
198+
final InputStream inputStream = new FileInputStream(xmlFilename.toFile());
199+
return inputFactory.createXMLEventReader(inputStream);
200+
}
201+
202+
}

0 commit comments

Comments
 (0)