插入式直接处理器 发表于 2018-07-31 插入式注解处理器 Sub:CheckStyle,FindBugs,Klocwork实现原理 一.API基础知识 AbstractProcessor ElementKind ProcessingEnvironment SupportedAnnotationTypes SupportedSourceVersion 二.eg代码 123456789101112131415161718192021222324252627282930313233343536373839404142434445import 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("*")//只支持JDK1.6的java代码@SupportedSourceVersion(SourceVersion.RELEASE_6)public class NameCheckProcessor extends AbstractProcessor { private NameChecker mNameChecker; /** * 初始换名称检查插件 * @param processingEnvironment */ @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); mNameChecker = new NameChecker(processingEnvironment); } /** * 对输入的语法树的各个节点进行名称检查 * @param set * @param roundEnvironment * @return */ @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { if (!roundEnvironment.processingOver()) { for (Element element : roundEnvironment.getRootElements()) { mNameChecker.checkNames(element); } } return false; }} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188import 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.Name;import javax.lang.model.element.TypeElement;import javax.lang.model.element.VariableElement;import javax.lang.model.util.ElementScanner6;import javax.tools.Diagnostic;import static javax.lang.model.element.Modifier.FINAL;import static javax.lang.model.element.Modifier.PUBLIC;import static javax.lang.model.element.Modifier.STATIC;/** * 程序名称规范的编译器插件 * 如果名称不符合规范,将会报出一个编译器的警告信息 * Created by zhouyibo on 2018/7/30. */public class NameChecker { private final Messager mMessager; private NameCheckScanner mNameCheckScanner = new NameCheckScanner(); public NameChecker(ProcessingEnvironment processingEnvironment) { mMessager = processingEnvironment.getMessager(); } /** * 对Java程序命名进行检查 * @param element */ public void checkNames(Element element) { mNameCheckScanner.scan(element); } /** * 名称检查实现类 继承ElementScanner6 * 将会以Visitor模式访问抽象语法树中的元素 */ private class NameCheckScanner extends ElementScanner6<Void, Void> { /** * 检查Java类 * @param typeElement * @param aVoid * @return */ @Override public Void visitType(TypeElement typeElement, Void aVoid) { scan(typeElement.getTypeParameters(), aVoid); checkCamelCase(typeElement, true); super.visitType(typeElement, aVoid); return null; } /** * 检查方法名 * @param executableElement * @param aVoid * @return */ @Override public Void visitExecutable(ExecutableElement executableElement, Void aVoid) { if (executableElement.getKind() == ElementKind.METHOD) { Name name = executableElement.getSimpleName(); if (name.contentEquals(executableElement.getEnclosingElement().getSimpleName())) { mMessager.printMessage(Diagnostic.Kind.WARNING, "一个普通方法" + name + "不应当与类名重复,避免与构造函数产生混淆", executableElement); checkCamelCase(executableElement, false); } } super.visitExecutable(executableElement, aVoid); return null; } /** * 检查变量命名 * @param variableElement * @param aVoid * @return */ @Override public Void visitVariable(VariableElement variableElement, Void aVoid) { if (variableElement.getKind() == ElementKind.ENUM_CONSTANT || variableElement.getConstantValue() != null || heuristicallyConstant(variableElement)) { checkAllCaps(variableElement); } else { checkCamelCase(variableElement, false); } return null; } /** * 大写命名检查 * @param e */ private void checkAllCaps(Element e) { String name = e.getSimpleName().toString(); boolean convertional = true; int firstCodePoint = name.codePointAt(0); if (!Character.isUpperCase(firstCodePoint)) { convertional = 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 == (int) '_') { if (previousUnderscore) { convertional = false; break; } previousUnderscore = true; } else { previousUnderscore = false; if (!Character.isUpperCase(cp) && !Character.isDigit(cp)) { convertional = false; break; } } } } if (!convertional) { mMessager.printMessage(Diagnostic.Kind.WARNING, "常量" + name + "应当全部以大写字母或者下划线命名,并且以字母开头", e); } } /** * 检查是都是常量 * @param variableElement * @return */ private boolean heuristicallyConstant(VariableElement variableElement) { if (variableElement.getEnclosingElement().getKind() == ElementKind.INTERFACE) { return true; } else if (variableElement.getKind() == ElementKind.FIELD && variableElement.getModifiers().containsAll(EnumSet.of(PUBLIC, STATIC, FINAL))) { return true; } else { return false; } } /** * 检查是否符合驼式命名 * @param e * @param b */ private void checkCamelCase(Element e, boolean b) { String name = e.getSimpleName().toString(); boolean previousUpper = false; boolean conventional = true; int firstCodePoint = name.codePointAt(0); if (Character.isUpperCase(firstCodePoint)) { previousUpper = true; if (!b) { mMessager.printMessage(Diagnostic.Kind.WARNING, "名称" + name + "应当以小写字母开头", e); return; } } else if (Character.isLowerCase(firstCodePoint)) { if (b) { mMessager.printMessage(Diagnostic.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) { mMessager.printMessage(Diagnostic.Kind.WARNING, "名称" + name + "应当符合驼式命名法", e); } } }}