自己动手编写java编译器
2013-08-20 23:19
190 查看
本篇博文来自于《深入理解Java虚拟机--JVM高级特性与最佳实践》一书。我们使用注解处理器API来编写一款拥有自己编码风格的代码校验工具:NameCheckProcessor.
java程序命名规范应当符合下列格式的书写规范:
1 类或接口:符合驼式命名法,首字母大写
2 方法:符合驼式命名法,首字母小写
3 字段
1)类或实例变量:符合驼式命名法,首字母小写
2)常量:要求全部由大写字母或下划线构成,并且第一个字母不能是下划线
代码实现:
注解处理器:NameCheckProcessor
命名检查器:NameChecker
java程序命名规范应当符合下列格式的书写规范:
1 类或接口:符合驼式命名法,首字母大写
2 方法:符合驼式命名法,首字母小写
3 字段
1)类或实例变量:符合驼式命名法,首字母小写
2)常量:要求全部由大写字母或下划线构成,并且第一个字母不能是下划线
代码实现:
注解处理器:NameCheckProcessor
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; /** * * @author Administrator * */ // 可以用"*"支持所有的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; } }
命名检查器:NameChecker
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; /** * 程序名称规范的编译器插件 如果程序名称不符合规范,则输出一个编译器的WARNING信息 * * @author Administrator * */ 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); } } }
相关文章推荐
- 利用unix网络编程知识自己动手编写一个chatroom程序中遇到的错误与解决
- 【C++ Primer】自己动手编写函数 atoi(char *str)
- 自己动手编写CSDN博客备份工具-blogspider之源码分析(2)
- 自己动手编写CSDN博客备份工具-blogspider之源码分析(1)
- 自己动手编写IoC容器(一)
- 自己动手编写CSDN博客备份工具-blogspider
- 自己动手编写FreeBSD内核防火墙模块
- 自己动手编写一个VS插件(三)——创建工具栏之一
- OWIN系列之自己动手编写中间件
- 自己动手编写IOC框架(二)
- D3D游戏编程系列(六):自己动手编写第一人称射击游戏之第一人称视角的构建
- 自己动手编写一个VS插件(七)
- 自己动手编写ssh登陆管理工具
- 【C++ Primer】自己动手编写函数 atoi(char *str)
- 自己动手编写CSDN博客备份工具-blogspider之源码分析(3)
- 自己动手编写CSDN博客备份工具-blogspider之源码分析(1)
- Android开发实践:自己动手编写图片剪裁应用(2)
- 自己动手编写FreeBSD内核防火墙模块
- 自己动手编写嵌入式Bootloader之(2)
- 动手编写自己的级联下拉列表 - 基础