自定义代码检查器-----Annotation实战【自定义AbstractProcessor】

原创
2017/01/14 16:15
阅读数 1.5K

##实战目标

  1. 类(或接口):符合驼式命名法,首字母大写。
  2. 方法: 符合驼式命名法,首字母小写。
  3. 字段:
  • 类或实例变量:符合驼式命名法,首字母小写。
  • 常量: 要求全部由大写字母或下划线构成,并且第一个字符不能使下划线。

####注册处理器NameCheckProcessor

package cn.zvc.processor;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

//可以用"*"支持所有的Annotations  
@SupportedAnnotationTypes("*")
// 只支持1.6的java代码
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class NameCheckProcessor extends AbstractProcessor {

	private NameChecker nameChecker;

	/**
	 * 初始化名称检查插件
	 */
	@Override
	public synchronized void init(ProcessingEnvironment processingEnv) {

		super.init(processingEnv);
		nameChecker = new NameChecker(processingEnv);
	}

	/**
	 * 对输入的语法树的各个节点进行名称检查
	 */
	@Override
	public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

		if (!roundEnv.processingOver()) {
			for (Element element : roundEnv.getRootElements()) {
				nameChecker.checkNames(element);
			}
		}

		return false;
	}
}

####命名检查器

package cn.zvc.processor;

import java.util.EnumSet;

import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementScanner6;
import javax.tools.Diagnostic.Kind;

public class NameChecker {
	private final Messager messager;  
	  
    NameCheckScanner nameCheckScanner = new NameCheckScanner();  
  
    public NameChecker(ProcessingEnvironment processingEnv) {  
  
        this.messager = processingEnv.getMessager();  
    }  
  
    /** 
     *  
     * 对java程序命名进行检查,java名称命名应符合如下格式: 
     * <ul> 
     * <li>类或接口:符合驼式命名法,首字母大写 
     * <li>方法:符合驼式命名法,首字母小写 
     * <li>字段:符合驼式命名法,首字母小写 
     * <li>类、实例变量:符合驼式命名法,首字母小写 
     * <li>常量:要求全部大写 
     * </ul> 
     *  
     */  
    public void checkNames(Element element) {  
  
        nameCheckScanner.scan(element);  
  
    }  
  
    /** 
     * 名称检查器实现类,继承了jdk1.6中新提供的ElementScanner6<br> 
     * 将会以Visitor模式访问抽象语法树中的元素 
     *  
     */  
    private class NameCheckScanner extends ElementScanner6<Void, Void> {  
  
        /** 
         * 此方法用于检查java类 
         */  
        @Override  
        public Void visitType(TypeElement e, Void p) {  
  
            scan(e.getTypeParameters(), p);  
            checkCamelCase(e, true);  
            super.visitType(e, p);  
            return null;  
        }  
  
        /** 
         * 检查方法命名是否合法 
         */  
        @Override  
        public Void visitExecutable(ExecutableElement e, Void p) {  
  
            if (e.getKind() == ElementKind.METHOD) {  
                Name name = e.getSimpleName();  
                if (name.contentEquals(e.getEnclosingElement().getSimpleName()))  
                    messager.printMessage(Kind.WARNING, " 一个普通方法 '" + name + "' 不应该与类名相同,避免与构造方法产生混淆", e);  
                checkCamelCase(e, false);  
            }  
  
            super.visitExecutable(e, p);  
            return null;  
        }  
  
        /** 
         * 检查变量命名是否合法 
         */  
        @Override  
        public Void visitVariable(VariableElement e, Void p) {  
  
            if (e.getKind() == ElementKind.ENUM_CONSTANT || e.getConstantValue() != null || heuristicallyConstant(e))  
                checkAllCaps(e);  
            else  
                checkCamelCase(e, false);  
  
            return null;  
        }  
  
        /** 
         * 判断一个变量是否是常量 
         *  
         * @param e 
         * @return 
         */  
        private boolean heuristicallyConstant(VariableElement e) {  
  
            if (e.getEnclosingElement().getKind() == ElementKind.INTERFACE)  
                return true;  
            else if (e.getKind() == ElementKind.FIELD  
                    && e.getModifiers().containsAll(EnumSet.of(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)))  
                return true;  
            else {  
                return false;  
            }  
        }  
  
        /** 
         * 检查传入的Element是否符合驼式命名法,如果不符合则输出警告信息 
         *  
         * @param e 
         * @param initialCaps 
         */  
        private void checkCamelCase(Element e, boolean initialCaps) {  
  
            String name = e.getSimpleName().toString();  
            boolean previousUpper = false;  
            boolean conventional = true;  
  
            int firstCodePoint = name.codePointAt(0);  
  
            if (Character.isUpperCase(firstCodePoint)) {  
                previousUpper = true;  
                if (!initialCaps) {  
                    messager.printMessage(Kind.WARNING, "名称  '" + name + " ' 应当以小写字母开头", e);  
                    return;  
                }  
            } else if (Character.isLowerCase(firstCodePoint)) {  
                if (initialCaps) {  
                    messager.printMessage(Kind.WARNING, "名称  '" + name + " ' 应当以大写字母开头", e);  
                    return;  
                }  
            } else  
                conventional = false;  
  
            if (conventional) {  
                int cp = firstCodePoint;  
                for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {  
                    cp = name.codePointAt(i);  
                    if (Character.isUpperCase(cp)) {  
                        if (previousUpper) {  
                            conventional = false;  
                            break;  
                        }  
                        previousUpper = true;  
                    } else  
                        previousUpper = false;  
                }  
  
            }  
            if (!conventional)  
                messager.printMessage(Kind.WARNING, "名称  '" + name + " ' 应当符合驼式命名法", e);  
  
        }  
  
        /** 
         * 大写命名检查,要求第一个字母是大写的英文字母,其余部分是大写字母或下划线 
         *  
         * @param e 
         */  
        private void checkAllCaps(VariableElement e) {  
  
            String name = e.getSimpleName().toString();  
            boolean conventional = true;  
  
            int firstCodePoint = name.codePointAt(0);  
  
            if (!Character.isUpperCase(firstCodePoint)) {  
                conventional = false;  
            } else {  
                boolean previousUnderscore = false;  
  
                int cp = firstCodePoint;  
                for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {  
                    cp = name.codePointAt(i);  
                    if (cp == '_') {  
                        if (previousUnderscore) {  
                            conventional = false;  
                            break;  
                        }  
                        previousUnderscore = true;  
                    } else {  
                        previousUnderscore = false;  
                        if (!Character.isUpperCase(cp) && !Character.isDigit(cp)) {  
                            conventional = false;  
                            break;  
                        }  
                    }  
                }  
            }  
            if (!conventional)  
                messager.printMessage(Kind.WARNING, "常量  '" + name + " ' 应当全部以大写字母或下划线命名,并且以字母开头", e);  
        }  
  
    }  
}

需要检查的代码

package cn.zvc.processor;

public class BADLY_NAME_CODE {

	enum colors{
		red, blue, green;
	}
	
	static final int _FORTY_TWO = 42;
	
	public static int NOT_A_CONSTANT = _FORTY_TWO;
	
	protected void BADLY_NAMED_CODE(){
		return ;
	}
	public void NOTCASEmethodNAME(){
		return;
	}
}

运行与测试

javac -encoding UTF-8 cn\zvc\processor\NameCheckProcessor.java

javac -encoding UTF-8 cn\zvc\processor\NameCheckProcessor.java

javac -processor cn.zvc.processor.NameCheckProcessor cn\zvc\processor\BADLY_NAME_CODE.java

结果

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部