zoukankan      html  css  js  c++  java
  • FindBugs检测器实现(2)

    FindBugs 检测器实现(1)中提到,FindBugs 主要有5类检测器,这篇日志介绍下FindBugs在类、方法、字段结构上的检测器实现。前面提到基于栈和简单的字节码模式要继承OpcodeStackDetector类,并实现sawOpcode方法用来检测每一个字节码。

    一般在写检测器之前,我们应该有一个自己想要检测的代码模式,但作为学习,这里使用一些简单的模式作为例子:

    1. 重写了equals函数,却没有重写hashCode函数。
    2. 经hashCode函数拼写为hashcode。

    FindBugs在类、方法、字段层面的检测器实现要继承PreorderDetector类,简单介绍些该类:

    PreorderVisitor

    PreorderVisitor继承了BetterVisitor,并在BetterVisitor的基础之上,添加了大量的方法用来从当前访问的类、方法或字段中获取信息,另外该类还提供了一些visitAfter方法,用来实现访问上的次序,在下面的例子中,我们会看到它的作用。像下面的方法PreorderVisitor中存在太多,这里就不一一列出,可能有些方法不能直接明了的知道其作用,大多可能是我们还不懂java的一些功能的缘故:

    public FieldDescriptor getFieldDescriptor()
    public MethodDescriptor getMethodDescriptor()
    public ClassDescriptor getClassDescriptor()
    public @SlashedClassName  String getClassName()
    public void visitAfter(Code obj)
    public void visitAfter(JavaClass obj)

    来个例子
    public class DemoPlugin extends PreorderDetector {
        private BugReporter bugReporter;
        
        public DemoPlugin(BugReporter reporter){
            bugReporter = reporter;
        }
    
        public boolean hasHashcode;
        public boolean hasEqual;
        public MethodAnnotation equals;
        
        @Override
        public void visit(JavaClass obj){
            System.out.println("visit class!!!!!!!!!" + obj.getClassName());
            hasHashcode = false;
            hasEqual = false;
            equals = null;
        }
        
        @Override
        public void visit(Method me){
            if(!me.isPublic())
                return;
            if("equals".equals(me.getName()) && "(Ljava/lang/Object;)Z".equals(me.getSignature())){
                hasEqual = true;
                System.out.println("find equals() method");
                equals = MethodAnnotation.fromVisitedMethod(this);
            }
            
            if("hashCode".equals(me.getName()) && "()I".equals(me.getSignature())){
                hasHashcode = true;
                System.out.println("find hashCode() method");
            }
            
            if("hashcode".equals(me.getName()) && "()I".equals(me.getSignature())){
                bugReporter.reportBug(new BugInstance(this, "HASHCODE WRONG SPELL", NORMAL_PRIORITY).
                        addClass(getDottedClassName()).addMethod(MethodAnnotation.fromVisitedMethod(this)));
            }
        }
        
        @Override
        public void visitAfter(JavaClass obj){
            if(hasEqual && !hasHashcode){
                BugInstance instance = new BugInstance(this, "EQUALS WITHOUT HASHCODE", NORMAL_PRIORITY).
                        addClass(getDottedClassName()).addMethod(equals);
                bugReporter.reportBug(instance);
            }
        }
    }

    这里我们继承了PreorderDetector,而PreorderDetector继承了PreorderVisitor,是因为BugInstance需要使用Detector进行实例,而PreorderDetector实现了Detector接口。

    上面方法我们使用了上个变量hasHashcode,hasEquals和equals,前两个变量用来保存当前访问的类是否存在hashCode和equals方法,第三个变量存放的是方法注释(要在报告bug中,这里先不管)。

    上述三个变量每次都在visit(JavaClass obj)方法中进行状态重置,这样才能对所有的类都进行检测。visit(Method me)方法中用来判断是否是equals、hashCode、hashcode方法,并修改相应的状态。如果是hashcode方法,则直接将该bug报告。

    visitAfter(JavaClass obj)方法执行时,已经对当前类检测完毕,这样可以判断是否出现equals方法,而没有出现hashCode方法的情况。

    将fandbugs.xml和massage.xml加到项目中打包,便能对我们定义的模式进行检测。

    以上仅是一个自定义在类、方法、字段层面上的检测器的一般步骤,例子仅是为了说明过程,只要我们熟悉我们想要检测的模式,就能通过上述方法实现。

  • 相关阅读:
    MYSQL定时任务 触发器
    mybatis 学习
    SSM 记录
    环境变量配置
    servlet 拦截器 (filter)
    验证码
    jquery $.ajax({});参数详解
    maven打包忽略静态资源解决办法,dispatchServlet拦截静态资源请求的解决办法
    switch..case..
    HDU 1005 题解
  • 原文地址:https://www.cnblogs.com/pzhblog/p/4528474.html
Copyright © 2011-2022 走看看