第10章+早期(编译器)优化+10.4 实战:插入式注解处理器
目录
10.4 实战:插入式注解处理器
10.4.3 代码实现
代码清单10-11, 注解处理器NameCheckProcessor
/*
* 代码清单10-11, 注解处理器NameCheckProcessor
*/
package cn.chapter10;
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("*")
//只支持JDK1.6的Java代码(我的是jdk1.7,所以我把书中SourceVersion.RELEASE_6改为SourceVersion.RELEASE_7)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class NameCheckProcessor extends AbstractProcessor{
private NameChecker nameChecker;
//初始化名称检查插件
@Override
public 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;
}
}
代码清单10-12, 命名检查器NameChecker
最后发现书上给的代码不完整,像METHOD,WARNING都没由给出定义,所以运行不了,郁闷!!!!!
/*
* 代码清单10-12, 命名检查器NameChecker
* 最后发现书上给的代码不完整,像METHOD,WARNING都没由给出定义,所以运行不了,郁闷!!!!!
*/
package cn.chapter10;
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.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementScanner7;
/*
* 程序名称规范的编译器插件:<br>
* 如果程序命名不和规范,将会输出一个编译器的WARNING信息
*/
public class NameChecker {
private final Messager messager;
NameCheckScanner nameCheckScanner = new NameCheckScanner();
NameChecker(ProcessingEnvironment processingEnv){
this.messager = processingEnv.getMessager();
}
/*
* 对java程序命名进行检查,根据《Java语言规范(第3版)》6.8节的要求,Java程序命名应当符合下列格式
* <u1>
* <li>类或接口:符合驼峰式命名法,首字符大写
* <li>方法:符合驼峰式命名法,首字符小写
* <li>字段:
* <u1>
* <li>类、实例变量:符合驼峰式命名法,首字符小写
* <li>常量:要求全部大写
* </u1>
* </u1>
*/
public void checkNames(Element element){
nameCheckScanner.scan(element);
}
/*
* 名称检查器实现类,继承了DJK1.7中新提供的ElementScanner7<br>
* 将会以Visitor模式访问抽象语法树中的元素
*/
private class NameCheckScanner extends ElementScanner7<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() == METHOD){
Name name = e.getSimpleName();
if(name.contentEquals(e.getEnclosingElement().getSimpleName()))
//messager.printMessage(WARNING, "一个普通方法"" + name + ""不应当与类名重复,避免与构造函数产生混淆",e);
messager.printMessage(WARNING, " 一个普通方法 " + name + " 不应当与类名重复,避免与构造函数产生混淆 ", e);
checkCamelCase(e, false);
}
super.visitExecutable(e, p);
return null;
}
//检查变量命名是否合法
@Override
public Void visitVariable(VariableElement e, Void p){
//如果这个Variable是枚举或常量,则按大写命名规则,否则按照驼峰式命名法规则检查
if(e.getKind() == ENUM_CONSTANT || e.getConstantValue() !=null || heuristicallyConstant(e))
checkAllCaps(e);
else
checkCamelCase(e, false);
return null;
}
//判断一个变量是否是常量
private boolean heuristicallyConstant(VariableElement e) {
if(e.getEnclosingElement().getKind() == INTERFACE)
return true;
else if(e.getKind() == FIELD &&e.getModifiers().containsAll(EnumSet.of(PUBLIC, STATIC, FINAL)))
return true;
else
return false;
}
//检查传入的Element是否符合驼峰式命名法,如果不符合,则输出警告信息
public 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(!initialCaps){
messager.printMessage(WARNING, "名称"+name+"应当以小写字母开头", e);
return;
}
}else if(Character.isLowerCase(firstCodePoint)){
if(initialCaps){
messager.printMessage(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(WARNING, "名称"+name+"应当符合驼峰式命名法(Camel case Names)", e);
}
//大写命名检查,要求第一个字母必须是大写的英文字母,其余部分可以是下划线或大写字母
private void checkAllCaps(Element 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 == (int)'_'){
if(previousUnderscore){
conventional = false;
break;
}
previousUnderscore = true;
}else{
previousUnderscore = false;
if(Character.isUpperCase(cp)&& !Character.isDigit(cp)){
conventional = false;
break;
}
}
}
}
if(!conventional)
messager.printMessage(WARNING, "名称"+name+"应当全部以大写字母或下划线命名,并且以字母开头", e);
}
}
}
10.4.3 运行与测试
代码清单10-13,包含了多处不规范命名的代码样例
/*
* 代码清单10-13,包含了多处不规范命名的代码样例
*/
package cn.chapter10;
public class BADLY_NAMED_CODE {
enum colors{
red, blue, green;
}
static final int _FORIY_TWO =42;
public static int NOT_A_CONSTANT = _FORIY_TWO;
protected void BADLY_NAME_CODE(){
return;
}
public void NOTcamelCASEmethodNAME(){
return;
}
}
代码清单10-14,注解处理器的运行过程,(都是错误!!!!)