mirror of
https://github.com/fenixsoft/jvm_book.git
synced 2025-03-13 10:41:20 +08:00
更新第10章名称检查器的测试代码
This commit is contained in:
parent
2c1288109e
commit
237d879035
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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user