自己动手编写java编译器

本文介绍了一款基于Java注解处理器的代码校验工具——NameCheckProcessor,它能够检查Java代码是否遵循驼峰命名法等命名规范。适用于类、接口、方法及变量等不同类型的元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇博文来自于《深入理解Java虚拟机--JVM高级特性与最佳实践》一书。我们使用注解处理器API来编写一款拥有自己编码风格的代码校验工具:NameCheckProcessor.

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);
		}

	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值