mirror of
https://github.com/fenixsoft/jvm_book.git
synced 2026-08-19 08:23:29 +08:00
更新第10章名称检查器的测试代码
This commit is contained in:
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**
|
||||||
|
!**/src/test/**
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
BIN
images/3-2.png
Normal file
BIN
images/3-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
BIN
images/3-3.png
Normal file
BIN
images/3-3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
images/Shenandoah.png
Normal file
BIN
images/Shenandoah.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
20
src/org/fenixsoft/jvm/chapter10/BADLY_NAMED_CODE.java
Normal file
20
src/org/fenixsoft/jvm/chapter10/BADLY_NAMED_CODE.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package org.fenixsoft.jvm.chapter10;
|
||||||
|
|
||||||
|
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 Test() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NOTcamelCASEmethodNAME() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/org/fenixsoft/jvm/chapter10/NameCheckProcessor.java
Normal file
38
src/org/fenixsoft/jvm/chapter10/NameCheckProcessor.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package org.fenixsoft.jvm.chapter10;
|
||||||
|
|
||||||
|
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_6)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
20
src/org/fenixsoft/jvm/chapter10/jdk8/BADLY_NAMED_CODE.java
Normal file
20
src/org/fenixsoft/jvm/chapter10/jdk8/BADLY_NAMED_CODE.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package org.fenixsoft.jvm.chapter10.jdk8;
|
||||||
|
|
||||||
|
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 Test() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NOTcamelCASEmethodNAME() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/org/fenixsoft/jvm/chapter10/jdk8/NameCheckProcessor.java
Normal file
38
src/org/fenixsoft/jvm/chapter10/jdk8/NameCheckProcessor.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package org.fenixsoft.jvm.chapter10.jdk8;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化名称检查插件
|
||||||
|
*/
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
181
src/org/fenixsoft/jvm/chapter10/jdk8/NameChecker.java
Normal file
181
src/org/fenixsoft/jvm/chapter10/jdk8/NameChecker.java
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
package org.fenixsoft.jvm.chapter10.jdk8;
|
||||||
|
|
||||||
|
import javax.annotation.processing.Messager;
|
||||||
|
import javax.annotation.processing.ProcessingEnvironment;
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.lang.model.util.ElementScanner6;
|
||||||
|
import javax.lang.model.util.ElementScanner7;
|
||||||
|
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类
|
||||||
|
*/
|
||||||
|
@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);
|
||||||
|
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是否符合驼式命名法,如果不符合,则输出警告信息
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user