Skip to content

Commit 6be8e63

Browse files
update project to java17
and add record checker
1 parent ce9b8c3 commit 6be8e63

File tree

8 files changed

+197
-0
lines changed

8 files changed

+197
-0
lines changed

pom.xml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@
4949
<timezone>-7</timezone>
5050
</developer>
5151
</developers>
52+
<properties>
53+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
54+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
55+
<maven.compiler.source>17</maven.compiler.source>
56+
<maven.compiler.target>17</maven.compiler.target>
57+
<maven.compiler.release>17</maven.compiler.release>
58+
</properties>
5259
<issueManagement>
5360
<system>GitHub</system>
5461
<url>https://github.com/yegor256/qulice/issues</url>
@@ -193,6 +200,35 @@
193200
</archive>
194201
</configuration>
195202
</plugin>
203+
<plugin>
204+
<groupId>org.apache.maven.plugins</groupId>
205+
<artifactId>maven-compiler-plugin</artifactId>
206+
<version>3.11.0</version>
207+
<configuration>
208+
<source>${maven.compiler.source}</source>
209+
<target>${maven.compiler.target}</target>
210+
<release>${maven.compiler.release}</release>
211+
<compilerArgs>
212+
<arg>--enable-preview</arg>
213+
</compilerArgs>
214+
</configuration>
215+
</plugin>
216+
<plugin>
217+
<groupId>org.apache.maven.plugins</groupId>
218+
<artifactId>maven-surefire-plugin</artifactId>
219+
<version>3.1.2</version>
220+
<configuration>
221+
<argLine>--enable-preview</argLine>
222+
</configuration>
223+
</plugin>
224+
<plugin>
225+
<groupId>org.apache.maven.plugins</groupId>
226+
<artifactId>maven-failsafe-plugin</artifactId>
227+
<version>3.1.2</version>
228+
<configuration>
229+
<argLine>--enable-preview</argLine>
230+
</configuration>
231+
</plugin>
196232
</plugins>
197233
</pluginManagement>
198234
</build>
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.qulice.checkstyle;
2+
3+
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
4+
import com.puppycrawl.tools.checkstyle.api.DetailAST;
5+
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
6+
7+
/**
8+
* Checks for proper record declarations.
9+
* Validates that:
10+
* 1. Records are properly declared with components
11+
* 2. Record components are properly formatted
12+
* 3. Records do not extend other classes
13+
* 4. Records are final
14+
*/
15+
public class RecordValidationCheck extends AbstractCheck {
16+
/**
17+
* A key is pointing to the warning message text in "messages.properties"
18+
* file.
19+
*/
20+
public static final String MSG_KEY = "record.validation";
21+
22+
@Override
23+
public int[] getDefaultTokens() {
24+
return new int[] {
25+
TokenTypes.RECORD_DEF,
26+
TokenTypes.RECORD_COMPONENT_DEF
27+
};
28+
}
29+
30+
@Override
31+
public int[] getAcceptableTokens() {
32+
return getDefaultTokens();
33+
}
34+
35+
@Override
36+
public int[] getRequiredTokens() {
37+
return getDefaultTokens();
38+
}
39+
40+
@Override
41+
public void visitToken(DetailAST ast) {
42+
switch (ast.getType()) {
43+
case TokenTypes.RECORD_DEF:
44+
checkRecordDeclaration(ast);
45+
break;
46+
case TokenTypes.RECORD_COMPONENT_DEF:
47+
checkRecordComponent(ast);
48+
break;
49+
}
50+
}
51+
52+
private void checkRecordDeclaration(DetailAST ast) {
53+
// Check if record extends another class
54+
if (ast.findFirstToken(TokenTypes.EXTENDS_CLAUSE) != null) {
55+
log(ast.getLineNo(), ast.getColumnNo(), "Records cannot extend other classes");
56+
}
57+
58+
// Check if record is final
59+
DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS);
60+
if (modifiers != null && modifiers.findFirstToken(TokenTypes.FINAL) == null) {
61+
log(modifiers.getLineNo(), modifiers.getColumnNo(), "Records must be final");
62+
}
63+
64+
// Check if record has components
65+
DetailAST components = ast.findFirstToken(TokenTypes.RECORD_COMPONENTS);
66+
if (components != null && components.findFirstToken(TokenTypes.RECORD_COMPONENT_DEF) == null) {
67+
log(components.getLineNo(), components.getColumnNo(), "Records must declare at least one component");
68+
}
69+
70+
checkRecordInstanceFields(ast);
71+
}
72+
73+
private void checkRecordInstanceFields(DetailAST ast) {
74+
DetailAST objBlockAst = ast.findFirstToken(TokenTypes.OBJBLOCK);
75+
76+
// Traverse the children of the objBlockAst to find variable definitions
77+
for (DetailAST child = objBlockAst.getFirstChild(); child != null; child = child.getNextSibling()) {
78+
if (child.getType() == TokenTypes.VARIABLE_DEF) {
79+
DetailAST modifiersAst = child.findFirstToken(TokenTypes.MODIFIERS);
80+
DetailAST isStatic = modifiersAst.findFirstToken(TokenTypes.LITERAL_STATIC);
81+
82+
if (isStatic == null) {
83+
log(child.getLineNo(), child.getColumnNo(), "Records cannot have instance fields");
84+
}
85+
}
86+
}
87+
}
88+
89+
private void checkRecordComponent(DetailAST ast) {
90+
// Check if component has a type
91+
if (ast.findFirstToken(TokenTypes.TYPE) == null) {
92+
log(ast.getLineNo(), ast.getColumnNo(), "Record component must have a type");
93+
}
94+
95+
// Check if component has a name
96+
if (ast.findFirstToken(TokenTypes.IDENT) == null) {
97+
log(ast.getLineNo(), ast.getColumnNo(), "Record component must have a name");
98+
}
99+
}
100+
}

qulice-checkstyle/src/test/java/com/qulice/checkstyle/ChecksTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ private void check(
151151
@SuppressWarnings("PMD.UnusedPrivateMethod")
152152
private static Stream<String> checks() {
153153
return Stream.of(
154+
"RecordValidationCheck",
154155
"MethodsOrderCheck",
155156
"MultilineJavadocTagsCheck",
156157
"StringLiteralsConcatenationCheck",
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright (c) 2011-2025 Yegor Bugayenko
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
package com.qulice.modern;
6+
7+
/**
8+
* Invalid record example.
9+
*/
10+
// Records must be final
11+
public record InvalidRecord() { // Records must declare at least one component
12+
private String extraField; // Records cannot have instance fields
13+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright (c) 2011-2025 Yegor Bugayenko
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
package com.qulice.modern;
6+
7+
/**
8+
* Valid record example.
9+
*
10+
* @since 1.0
11+
*/
12+
public final record ValidRecord(String name, int age) {
13+
/**
14+
* Constructor.
15+
* @param name Name
16+
* @param age Age
17+
*/
18+
public ValidRecord {
19+
if (name == null || name.isEmpty()) {
20+
throw new IllegalArgumentException("Name cannot be empty");
21+
}
22+
if (age < 0) {
23+
throw new IllegalArgumentException("Age cannot be negative");
24+
}
25+
}
26+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0"?>
2+
<!DOCTYPE module PUBLIC
3+
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
4+
"https://checkstyle.org/dtds/configuration_1_3.dtd">
5+
<module name="Checker">
6+
<module name="TreeWalker">
7+
<module name="com.qulice.checkstyle.RecordValidationCheck"/>
8+
</module>
9+
</module>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
10:Records must be final
2+
10:Records must declare at least one component
3+
11:Records cannot have instance fields

qulice-maven-plugin/pom.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@
1313
<artifactId>qulice-maven-plugin</artifactId>
1414
<packaging>maven-plugin</packaging>
1515
<name>qulice-maven-plugin</name>
16+
17+
<properties>
18+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
19+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20+
<maven.compiler.source>17</maven.compiler.source>
21+
<maven.compiler.target>17</maven.compiler.target>
22+
<maven.compiler.release>17</maven.compiler.release>
23+
</properties>
24+
1625
<dependencies>
1726
<dependency>
1827
<groupId>org.cactoos</groupId>

0 commit comments

Comments
 (0)