第10章+早期(编译器)优化+10.4 实战:插入式注解处理器

目录

10.4 实战:插入式注解处理器

10.4.3 代码实现

10.4.3 运行与测试


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章+早期(编译器)优化+10.4 实战:插入式注解处理器

代码清单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章+早期(编译器)优化+10.4 实战:插入式注解处理器

10.4.3 运行与测试

第10章+早期(编译器)优化+10.4 实战:插入式注解处理器

 代码清单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,注解处理器的运行过程,(都是错误!!!!

第10章+早期(编译器)优化+10.4 实战:插入式注解处理器