插入式注解处理器

news/2024/12/1 14:43:08/文章来源:https://www.cnblogs.com/hellodeyang/p/18565997

实战:插入式注解处理器

目标:检查是否符合驼式命名法

详细描述查看【深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)】10.4 实战:插入式注解处理器(510页)

1.代码部分

1.注解处理器

NameCheckProcessor

package org.anno;import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.util.Set;// 可以用"*"表示支持所有Annotations
@SupportedAnnotationTypes("*")
// 只支持JDK 6的Java代码
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class NameCheckProcessor extends AbstractProcessor {private NameChecker nameChecker;/*** 初始化名称检查插件*/@Overridepublic void init(ProcessingEnvironment processingEnv) {super.init(processingEnv);nameChecker = new NameChecker(processingEnv);}/*** 对输入的语法树的各个节点进行名称检查*/@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {if (!roundEnv.processingOver()) {for (Element element : roundEnv.getRootElements())nameChecker.checkNames(element);}return false;}}
2.命名检查器

NameChecker

package org.anno;import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.*;
import javax.lang.model.util.ElementScanner8;import java.util.EnumSet;import static javax.lang.model.element.ElementKind.*;
import static javax.lang.model.element.Modifier.*;
import static javax.tools.Diagnostic.Kind.WARNING;/*** 程序名称规范的编译器插件:<br>* 如果程序命名不合规范,将会输出一个编译器的WARNING信息*/
public class NameChecker {private final Messager messager;NameCheckScanner nameCheckScanner = new NameCheckScanner();NameChecker(ProcessingEnvironment processsingEnv) {this.messager = processsingEnv.getMessager();}/**** 对Java程序命名进行检查,根据《Java语言规范》第三版第6.8节的要求,Java程序命名应当符合下列格式:** <ul>* <li>类或接口:符合驼式命名法,首字母大写。* <li>方法:符合驼式命名法,首字母小写。* <li>字段:* <ul>* <li>类、实例变量: 符合驼式命名法,首字母小写。* <li>常量: 要求全部大写。* </ul>* </ul>*/public void checkNames(Element element) {nameCheckScanner.scan(element);}/*** 名称检查器实现类,继承了JDK 6中新提供的ElementScanner6<br>* 将会以Visitor模式访问抽象语法树中的元素*/private class NameCheckScanner extends ElementScanner8<Void, Void> {/*** 此方法用于检查Java类*/@Overridepublic Void visitType(TypeElement e, Void p) {scan(e.getTypeParameters(), p);checkCamelCase(e, true);super.visitType(e, p);return null;}/*** 检查方法命名是否合法*/@Overridepublic Void visitExecutable(ExecutableElement e, Void p) {if (e.getKind() == METHOD) {Name name = e.getSimpleName();if (name.contentEquals(e.getEnclosingElement().getSimpleName()))messager.printMessage(WARNING, "一个普通方法 " + name + "不应当与类名重复,避免与构造函数产生混淆");checkCamelCase(e, false);}super.visitExecutable(e, p);return null;}/*** 检查变量命名是否合法*/@Overridepublic Void visitVariable(VariableElement e, Void p) {// 如果这个Variable是枚举或常量,则按大写命名检查,否则按照驼式命名法规则检查if (e.getKind() == ENUM_CONSTANT || e.getConstantValue() != null || heuristicallyConstant(e))checkAllCaps(e);elsecheckCamelCase(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是否符合驼式命名法,如果不符合,则输出警告信息*/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(WARNING, "名称" + name + "应当以小写字母开头", e);return;}} else if (Character.isLowerCase(firstCodePoint)) {if (initialCaps) {messager.printMessage(WARNING, "名称" + name + "应当以大写字母开头", e);return;}} elseconventional = 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;} elsepreviousUpper = 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);}}
}
3.不规范命名的代码
package org.anno;public class BADLY_NAMED_CODE {enum colors {red, blue, green;}static final int _FORTY_TWO = 42;public static int NOT_A_CONSTANT = _FORTY_TWO;protected void BADLY_NAMED_CODE() {return;}public void NOTcamelCASEmethodNAME() {return;}
}

2.运行与测试

待编译的类目录:D:\ToolOfProductionData\IDEAFile\DemoTest\src\main\java\org\anno

1.运行测试

注意:因为有包名的缘故,如果直接在包下执行javac或者java 这样是找不到class文件的。

解决:去对应项目的java目录下执行命令 例如:cd D:\ToolOfProductionData\IDEAFile\DemoTest\src\main\java

d:
cd D:\ToolOfProductionData\IDEAFile\DemoTest\src\main\java
javac org/anno/NameChecker.java
有编码问题是则使用:javac -encoding utf-8 org/anno/NameChecker.java
javac org/anno/NameCheckProcessor.javajavac -processor org.anno.NameCheckProcessor org\anno\BADLY_NAMED_CODE.java
有编码问题是则使用:
javac -processor org.anno.NameCheckProcessor -encoding utf-8 org\anno\BADLY_NAMED_CODE.java

运行效果图

注意:javac编译问题

因为有包名的缘故,如果直接在包下执行javac或者java 这样是找不到 class文件的。

解决:去对应项目的java目录下执行命令 例如:D:\ToolOfProductionData\IDEAFile\DemoTest\src\main\java

详细请看:javac编译问题_找不到注释处理程序-CSDN博客

编译条件

待编译的类目录:D:\ToolOfProductionData\IDEAFile\DemoTest\src\main\java\org\anno

1.中文乱码

javac NameChecker.java

改成:

javac -encoding utf-8 NameChecker.java

2.引用其他类的时候,报找不到符号

(1)javac -encoding utf-8 *.java

(2) 换到src\main\java目录下:cd C:\work\workspace\my\my-utils\src\main\java

javac -encoding utf-8 com/my/jvm/processor/NameCheckProcessor.java

3.javac -processor报错

(1)java.lang.NoClassDefFoundError: NameCheckProcessor (wrong name: com/my/jvm/processor/NameCheckProcessor)

javac -processor NameCheckProcessor -encoding utf-8 .\BADLY_NAMED_CODE.java

(2)错误: 找不到注释处理程序 'com.my.jvm.processor.NameCheckProcessor'

javac -processor com.my.jvm.processor.NameCheckProcessor -encoding utf-8 .\BADLY_NAMED_CODE.java

因为有包名的缘故,如果直接在包下执行javac或者java 这样是找不到 class文件的。

解决:

cd  C:\work\workspace\my\my-utils\src\main\javajavac  -processor com.my.jvm.processor.NameCheckProcessor  -encoding utf-8  com\my\jvm\processor\BADLY_NAMED_CODE.java

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/844570.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

洛谷P11361 [NOIP2024] 编辑字符串

ProblemSolve 首先任意更换相邻元素任意次等同于在可交换范围内随便移动 这题是求最优解,直观想到DP和贪心,但是容易反应过来本题DP的话很难做到无后效性,且状态较多,故尝试贪心 不难发现,我们从左往右遍历的某个时刻进行交换后所得到的局部最优解总是答案的一种方案的一部…

JVM学习-02-Java内存区域与内存溢出异常

第二章、Java内存区域与内存溢出异常2.1 概述介绍Java虚拟机内存的各个区域 讲解这些区域的作用、服务对象以及其中可能产生的问题2.2 运行时数据区域 2.2.1 运行时数据区域程序计数器:当前线程所执行的字节码的行号指示器,每条线程都需要有一个独立的程序计数器(线程私有)…

2024-2025-1 学号20241315《计算机基础与程序设计》第十周学习总结

作业信息这个作业属于哪个课程 2024-2025-1-计算机基础与程序设计这个作业要求在哪里 <作业要求的链接>(https://www.cnblogs.com/rocedu/p/9577842.html#WEEK10)这个作业的目标 信息系统 数据库与SQL 人工智能与专家系统 人工神经网络 模拟与离散事件 排队系统 天气与地…

计算机基础与程序设计第十周总结

学期(如2024-2025-1) 学号(如:20241300) 《计算机基础与程序设计》第X周学习总结 作业信息这个作业属于哪个课程 https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP这个作业要求在哪里 https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP/homework/13273这个作…

高级语言程序设计第九次个人作业

这个作业属于哪个课程:https://edu.cnblogs.com/campus/fzu/2024C 这个作业要求在哪里: https://edu.cnblogs.com/campus/fzu/2024C/homework/13311 学号:102400111 姓名:蔡伟仡 14.17.314.17.414.17.514.17.1014.17.1114.18.314.18.414.18.5总结与反思:熟悉枚举和共用体

20222412 2021-2022-2 《网络与系统攻防技术》实验七实验报告

20222412 2021-2022-2 《网络与系统攻防技术》实验七实验报告 1.实验内容 本实践的目标理解常用网络欺诈背后的原理,以提高防范意识,并提出具体防范方法。具体实践有 (1)简单应用SET工具建立冒名网站 SET工具是一款开源的社会工程学渗透测试工具,专门用于模拟各种社会工程…

2024-2025-1 20241411王思棋《计算机基础与程序设计》第十周学习总结

作业信息 |这个作业属于哪个课程|https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP| | -- |-- | |这个作业要求在哪里|https://www.cnblogs.com/rocedu/p/9577842.html#WEEK10| | 这个作业的目标|信息系统、数据库与SQL、人工智能与专家系统、人工神经网络、模拟与离散事…

2024-2025-1 20241421 刘庆安《计算机基础与程序设计》第十周学习总结

这个作业属于哪个课程 2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 https://www.cnblogs.com/rocedu/p/9577842.html#WEEK10这个作业的目标 信息系统、数据库与SQL、人工智能与专家系统、人工神经网络、模拟与离散事件、排队系统、天气与地震模型、图形图像作业正文…

消费占GDP比重

import matplotlib.pyplot as plt from pylab import mpl# 设置matplotlib支持中文字体 mpl.rcParams["font.sans-serif"] = ["SimHei"] # Windows系统使用黑体 # mpl.rcParams["font.sans-serif"] = ["Arial Unicode MS"] # macOS系…

20241313 刘鸣宇 《计算机基础与程序设计》第十周学习总结

2024-2025-1 20241313 《计算机基础与程序设计》第十周学习总结 作业信息这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>(如2024-2025-1计算机基础与程序设计第一周作业)这个作业的目标 <写上具…

同步时钟,异步时钟

synchronous & asynchronous 在静态时序分析中,有一个很重要的概念是同步和异步 如果 launch clock 与 capture clock 有固定的相位差,那就是同步时序 如果两者没有固定的相位差,那就是异步时序 一般情况下,STA 只检查同步时序,不用检查异步时序 同步时序又分为以下几…

Python数据爬取处理可视化,手把手全流程教学

这篇博客中,选取openjudge网站上“百练”小组中的用户答题数据,作为材料进行教学目录爬取主页面内容主页面内容提取需求数据爬取数据处理数据分析 网站地址:http://bailian.openjudge.cn/使用到的Python包:requests、pandas、re、BeautifulSoup、time、matplotlib、seaborn…