Hầu hết câu trả lời này được lấy cảm hứng từ Checkstyle's "Writing Checks" article. Hầu hết công việc được thực hiện trong AnnotationSameLineCheck
.
AnnotationSameLineCheck.java
tập Java này được lấy cảm hứng từ "Visitor In Action" section của "Kiểm tra Viết" bài viết.
getDefaultTokens
xác định phần nào (a.k.a. mã thông báo) của tệp Java mà chúng tôi quan tâm. Đầu tiên, chúng tôi có thể nghĩ rằng chúng tôi muốn quan tâm đến TokenTypes.ANNOTATION
, nhưng điều này không đúng. Chúng tôi không quan tâm đến TokenTypes.ANNOTATION
vì chúng tôi không muốn kiểm tra tất cả các chú thích; chúng tôi thực sự muốn bỏ qua TokenTypes.PARAMETER_DEF
.
Chúng tôi quan tâm đến điều gì sau đó? Chúng tôi thực sự quan tâm đến những phần của tệp Java có thể được chú thích (tức là định nghĩa lớp TokenTypes.CLASS_DEF
, định nghĩa phương thức TokenTypes.METHOD_DEF
, v.v.). Thuận tiện, API của Checkstyle có một phương thức có thể cho chúng tôi biết mã thông báo có được chú thích hay không. Phương pháp đó là AnnotationUtility.containsAnnotation
, được sử dụng trong visitToken
.
Các thuật toán sử dụng để xác định xem chú thích là trên cùng một dòng như các bộ phận khác của một file Java là như sau:
- Xác định xem một thẻ đặc biệt có chứa một chú thích. Nếu không, đừng làm gì cả.
- Tìm mã thông báo chú thích.
- Tìm mã thông báo trước mã thông báo chú thích.
- Tìm mã thông báo sau mã thông báo chú thích.
- Nếu mã thông báo chú thích nằm trên cùng một dòng với mã thông báo trước đó, hãy đăng nhập lỗi.
- Nếu mã thông báo chú thích nằm trên cùng một dòng với mã thông báo tiếp theo, hãy đăng nhập lỗi.
Thuật toán này được tìm thấy trong visitToken
.
package example;
import com.puppycrawl.tools.checkstyle.api.AnnotationUtility;
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
public class AnnotationSameLineCheck extends Check {
@Override
public int[] getDefaultTokens() {
// PACKAGE_DEF and PARAMETER_DEF were left out of the list
return new int[] { TokenTypes.ANNOTATION_DEF, //
TokenTypes.ANNOTATION_FIELD_DEF, //
TokenTypes.CLASS_DEF, //
TokenTypes.CTOR_DEF, //
TokenTypes.ENUM_DEF, //
TokenTypes.ENUM_CONSTANT_DEF, //
TokenTypes.INTERFACE_DEF, //
TokenTypes.METHOD_DEF, //
TokenTypes.VARIABLE_DEF };
}
@Override
public void visitToken(DetailAST ast) {
if (AnnotationUtility.containsAnnotation(ast)) {
final DetailAST holder = AnnotationUtility.getAnnotationHolder(ast);
final DetailAST annotation = getAnnotationAst(holder);
final DetailAST prev = getPreviousSibling(annotation, holder, ast);
final DetailAST next = getNextSibling(annotation, holder, ast);
if (isPreviousSiblingOnSameLine(prev, annotation) || //
isNextSiblingOnSameLine(annotation, next)) {
log(annotation.getLineNo(), //
annotation.getColumnNo(), //
"Annotations must exist on their own line");
}
}
}
private static boolean isPreviousSiblingOnSameLine(DetailAST prev, DetailAST annotation) {
if (prev == null) {
return false;
} else if (prev.getLastChild() == null) {
return prev.getLineNo() == annotation.getLineNo();
}
return prev.getLastChild().getLineNo() == annotation.getLineNo();
}
private static boolean isNextSiblingOnSameLine(DetailAST annotation, DetailAST next) {
if (next == null) {
return false;
}
return annotation.getLineNo() == next.getLineNo();
}
private static DetailAST getAnnotationAst(DetailAST aHolderAst) {
if (aHolderAst.getType() == TokenTypes.ANNOTATIONS) {
return aHolderAst;
} else if (aHolderAst.getType() == TokenTypes.MODIFIERS) {
return aHolderAst.findFirstToken(TokenTypes.ANNOTATION);
}
throw new AssertionError("aHolder must be one of TokenTypes.ANNOTATIONS or TokenTypes.MODIFIERS but was " + aHolderAst);
}
private static DetailAST getPreviousSibling(DetailAST annotation, DetailAST holder, DetailAST ast) {
if (annotation.getPreviousSibling() != null) {
return annotation.getPreviousSibling();
} else if (holder.getPreviousSibling() != null) {
return holder.getPreviousSibling();
}
return ast.getPreviousSibling();
}
private static DetailAST getNextSibling(DetailAST annotation, DetailAST holder, DetailAST ast) {
if (annotation.getNextSibling() != null) {
return annotation.getNextSibling();
} else if (holder.getNextSibling() != null) {
return holder.getNextSibling();
}
return ast.getNextSibling();
}
}
checks.xml tập tin
XML này được lấy cảm hứng từ "Integrate Your Check" section của "Kiểm tra Viết" bài viết. Nó được sử dụng bởi Checkstyle để chỉ định kiểm tra nào để thực hiện trên một tập hợp các tệp Java. Lưu ý rằng AnnotationSameLineCheck
hoàn toàn đủ điều kiện (nghĩa là, gói của nó được chỉ định trong tên). checks.xml
được đề cập trong tệp build.xml
.
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="TreeWalker">
<module name="example.AnnotationSameLineCheck"/>
</module>
</module>
xây dựng.xml
Tệp xây dựng Ant này được lấy cảm hứng từ Checkstyle's "Ant Task" article. Sử dụng Ant chỉ là một cách để thực thi Checkstyle. Sử dụng dòng lệnh là một tùy chọn khác.
<project default="example">
<taskdef resource="checkstyletask.properties" classpath="target/classes:lib/checkstyle-5.5-all.jar" />
<target name="example">
<checkstyle config="checks.xml">
<fileset dir="src/main/java" includes="**/AnnotatedClass.java" />
<formatter type="plain" />
</checkstyle>
</target>
</project>
AnnotationClass.java
Người ta có thể sử dụng lớp sau đây để kiểm tra AnnotationSameLineCheck
. Nó được đề cập trong tập tin build.xml
. Lưu ý việc kiểm tra giao diện, lớp, enum, biến thành viên, phương thức, tham số và khai báo biến cục bộ.
package example;
@Deprecated
class CorrectClassDefA {}
@Deprecated class IncorrectClassDefA {}
abstract
@Deprecated
class CorrectClassDefB {}
abstract @SuppressWarnings(value = "unused") class IncorrectClassDefB0 {}
abstract
@Deprecated class IncorrectClassDefB1 {}
[email protected]
class IncorrectClassDefB2 {}
@Deprecated abstract class IncorrectClassDefB3 {}
@Deprecated
abstract class CorrectClassDefB4 {}
@SuppressWarnings(value = "unused")
interface CorrectInterfaceDefA {}
@Deprecated interface IncorrectInterfaceDefA {}
abstract
@Deprecated
interface CorrectInterfaceDefB {}
abstract @Deprecated interface IncorrectInterfaceDefB0 {}
abstract
@Deprecated interface IncorrectInterfaceDefB1 {}
abstract @SuppressWarnings(value = "unused")
interface IncorrectInterfaceDefB2 {}
@SuppressWarnings(value = "unused") abstract interface IncorrectInterfaceDefB3 {}
@SuppressWarnings(value = "unused")
abstract
interface CorrectInterfaceDefB4 {}
@Deprecated
enum CorrectEnumA {
@SuppressWarnings(value = "unused")
CORRECT,
@Deprecated INCORRECT }
@Deprecated enum
IncorrectEnumA {
@Deprecated
CORRECT,
@SuppressWarnings(value = "unused") INCORRECT }
public class AnnotatedClass { @Deprecated // incorrect
public AnnotatedClass() {}
@Deprecated
AnnotatedClass(int correct) {}
public
@SuppressWarnings(value = "unused")
AnnotatedClass(boolean correct, boolean correct0) {}
@SuppressWarnings(value = "unused")
AnnotatedClass(int correct, int correct0, int correct1) {}
public @SuppressWarnings(value = "unused")
AnnotatedClass(@Deprecated int bad, int bad0, int bad1, int bad2) {}
@SuppressWarnings(value = "unused") AnnotatedClass(@Deprecated int bad, int bad0, int bad1, int bad2, int bad3) {}
@Deprecated private int incorrectB;
transient @Deprecated
private int incorrectC;
transient
@Deprecated
private
int correctD;
private
@SuppressWarnings(value = "unused")
Object correctA; @SuppressWarnings(value = "dog")
public void incorrectA(final Object baz) {
}
public void correctB(@SuppressWarnings(value = "dog") final Object good) {
@Deprecated
int correctA;
final @Deprecated int incorrectB;
final
@Deprecated
Object
correctC;
}
@SuppressWarnings(value = "dog") public
void incorrectC(final Object bad) {
}
public
@SuppressWarnings(value = "dog") void incorrectD(final Object bad) {
}
}
Chế độ kiểm tra dường như có API khá linh hoạt, vì vậy tôi tưởng tượng điều đó là có thể. Bạn đã thử cái gì? –
Tôi đã thử tạo regexp, nhưng không thể viết đúng –
bạn có thể viết regexp của mình trong câu hỏi của mình không, vì vậy chúng tôi có thể xác định chính xác điều gì? – zmo