Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java “的检查样式规则”@注释必须在单独的行“中”;_Java_Annotations_Checkstyle - Fatal编程技术网

Java “的检查样式规则”@注释必须在单独的行“中”;

Java “的检查样式规则”@注释必须在单独的行“中”;,java,annotations,checkstyle,Java,Annotations,Checkstyle,我正在尝试为checkstyle创建一个规则,该规则将防止在使用时编写内联注释,如下所示: @Entity MyClass someEntity; @Foo(a="B") public void bar(Baz baz) { } 但不会阻止这样的想法: public void bar(@Param Baz baz) { } 有什么办法可以做到这一点吗?这个答案的大部分灵感来自于。大部分工作是在注释SamelineCheck中完成的 注释SamelineCheck.java 这个Java文件的

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

@Entity MyClass someEntity;
@Foo(a="B") public void bar(Baz baz) {
}
但不会阻止这样的想法:

public void bar(@Param Baz baz) {
}

有什么办法可以做到这一点吗?

这个答案的大部分灵感来自于。大部分工作是在
注释SamelineCheck
中完成的

注释SamelineCheck.java

这个Java文件的灵感来自于“编写检查”文章的主题

getDefaultTokens
定义我们感兴趣的Java文件的哪些部分(也称为令牌)。首先,人们可能会认为我们对
TokenTypes.ANNOTATION
感兴趣,但事实并非如此。我们对
TokenTypes.ANNOTATION
不感兴趣,因为我们不想检查所有注释;我们实际上想要忽略
标记类型。参数_DEF

那么我们对什么感兴趣呢?实际上,我们对Java文件中可以注释的部分感兴趣(即类定义
TokenTypes.class_DEF
、方法定义
TokenTypes.method_DEF
),等等)。方便的是,Checkstyle的API有一个方法可以告诉我们是否对令牌进行了注释。该方法是
AnnotationUtility.containsAnotation
,用于
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();
    }
}
用于确定注释是否与Java文件的其他部分位于同一行的算法如下:

  • 确定特定标记是否包含注释。如果没有,什么也不做
  • 查找注释标记
  • 在注释标记之前查找标记
  • 在注释标记后查找标记
  • 如果注释标记与上一个标记位于同一行,则记录错误
  • 如果注释标记与下一个标记位于同一行,则记录错误
  • 此算法可在
    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文件的灵感来自于“编写支票”一文的主题。Checkstyle使用它来指定对一组Java文件执行哪些检查。请注意,
    AnnotationSameLineCheck
    是完全限定的(即,其包在名称中指定)
    checks.xml
    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>
    

    Checkstyle似乎有一个相当灵活的API,所以我认为这是可能的。你试过什么?我试过创建regexp,但写得不对。你能在你的问题中写下你的regexp吗?这样我们就可以找出问题所在了?我觉得奇怪的是,你想阻止方法参数的内联注释。对我来说,这似乎是最干净的方式。我不确定使用正则表达式是否可行。它们可能不足以验证诸如
    @Foo(a=“\”)公共空白条(Baz-Baz)之类的内容{“”
    。您可能需要AST访问者。我也同意此规则不是很好的主意,但如果您真的必须这样做,请尝试做一些较弱的操作。只需假设注释参数中没有括号。那么它看起来很容易让人印象深刻!感谢您提供详细的答案!我很乐意在我们的网站上托管您的代码,请提供帮助
    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) {
        }
    }