gpt4 book ai didi

java - "@annotations must be on separate line"的 Checkstyle 规则

转载 作者:搜寻专家 更新时间:2023-10-30 21:27:41 25 4
gpt4 key购买 nike

我正在尝试为 checkstyle 创建一个规则,它将阻止编写内联注释用法,如下所示:

@Entity MyClass someEntity;
@Foo(a="B") public void bar(Baz baz) {
}

但不会阻止这样的想法:

public void bar(@Param Baz baz) {
}

有什么办法可以实现吗?

最佳答案

这个答案的大部分灵感来自 Checkstyle's "Writing Checks" article .大部分工作在 AnnotationSameLineCheck 中完成。

AnnotationSameLineCheck.java

此 Java 文件的灵感来自 "Visitor In Action" section “写作检查”一文。

getDefaultTokens 定义了我们对 Java 文件的哪些部分(也称为标记)感兴趣。第一个可能认为我们会对 TokenTypes.ANNOTATION 感兴趣, 但这种情况并非如此。我们对 TokenTypes.ANNOTATION 不感兴趣,因为我们不想检查所有注释;我们实际上想要忽略 TokenTypes.PARAMETER_DEF

那我们对什么感兴趣呢?我们实际上对 Java 文件中可以注释的那些部分感兴趣(即类定义 TokenTypes.CLASS_DEF、方法定义 TokenTypes.METHOD_DEF 等)。方便的是,Checkstyle 的 API 有一个方法可以告诉我们 token 是否被注释。那个方法是AnnotationUtility.containsAnnotation,在visitToken中使用。

判断一个注解是否与Java文件的其他部分在同一行的算法如下:

  1. 确定特定标记是否包含注释。如果没有,什么也不做。
  2. 找到注释标记。
  3. 找到注释标记之前的标记。
  4. 在注释标记之后找到标记。
  5. 如果注释标记与前一个标记在同一行,记录错误。
  6. 如果注释标记与下一个标记在同一行,记录错误。

这个算法可以在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

此 XML 文件的灵感来自 "Integrate Your Check" section “写作检查”一文。 Checkstyle 使用它来指定对一组 Java 文件执行哪些检查。请注意,AnnotationSameLineCheck 是完全限定的(即,它的包在名称中指定)。 checks.xmlbuild.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>

build.xml

此 Ant 构建文件的灵感来自 Checkstyle's "Ant Task" article .使用 Ant 只是执行 Checkstyle 的一种方式。使用命令行是另一种选择。

<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>

注释类.java

可以使用下面的类来测试AnnotationSameLineCheckbuild.xml 文件中提到了它。注意接口(interface)、类、枚举、成员变量、方法、参数和局部变量声明的测试。

package example;
@Deprecated
class CorrectClassDefA {}

@Deprecated class IncorrectClassDefA {}

abstract
@Deprecated
class CorrectClassDefB {}

abstract @SuppressWarnings(value = "unused") class IncorrectClassDefB0 {}

abstract
@Deprecated class IncorrectClassDefB1 {}

abstract@Deprecated
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) {
}
}

关于java - "@annotations must be on separate line"的 Checkstyle 规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10636563/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com