java编译器代码检查_java 命名代码检查-注解处理器
命名代碼檢查
根據 中第6.8節的要求, Java 程序命名應當符合下列格式的書寫規范:
類 ( 或接口 ) : 符合駝式命名法, 首字母大寫.
方法 : 符合駝式命名法,首字母小寫
字段 :類或實例變量 : 符合駝式命名法 , 首字母小寫
常量 : 要求全部有大寫字母或下劃線構成, 并且第一個字符不能是下劃線.
要通過注解處理器的API 實現一個編譯器插件 , 首先需要了解這組 API 的基本知識.我們實現注解處理器的代碼需要繼承抽象類 javax.annotation.processing.AbstractProcessor ,這個抽象類中只有一個必須覆蓋的abstract方法 : "process()" ?它是 javac 編譯器在執行注解處理器代碼時需要調用的過程 , 我們可以從這個方法的第一個參數 'annotations' 中獲取到此注解處理器所要求處理的注解集合,從第二個參數 'roundEnv' 中訪問到當前這個 round 中得語法樹節點, 每個語法樹節點在這里表示為一個 Element ?, 在 JDK1.6 新增的 javax.lang.model 包中定義了16類 Element , 包括了 Java 代碼中最常用的元素,
如 : '包( PACKAGE ) , 枚舉 ( ENUM ) ?, 類 ( CLASS ) , 注解 (ANNOTATION_TYPE) , 接口 (INTERFACE ) , 枚舉值 ( ENUM_VARIABLE ) ,字段 ( FIELD ) , 參數 ( PARAMETER ) , 本地變量 ( LOCAL_VARIABLE ) , 異常 ( EXCEPTOIN_PARAMETER ) ?,方法 ( METHOD ) , 構造函數 (CONSTRUCTOR ) 靜態塊語句 ( STATIC_INIT ,即 static {} 塊 ) ,實例語句塊 (INSTANCE_INIT, 即{}塊) , 參數化類型 ( TYPE_PARAMETER ) , 和未定義的其他語法樹節點 ( OTHER ) ;
除了 process () 方法的傳入參數之外, 還有一個很常用的實例變量' processingEnv' ,它是 AbstractProcessor 中的一個 protected 變量, 在注解處理器代碼可以直接訪問到它,它代表了注解處理器框架提供了一個上下文環境,眼創建新的代碼,向編譯器輸出信息,獲取其他工具類等都需要用到這個實例變量,
注解處理器除了 process 方法及其參數外,還有兩個可以配合使用的 Annotations :@SupportedAnnotationTypes 和@SupportedSourceVersion 前者代表這個注解處理器對哪些注解感興趣,可以使用 '*' 作為通配符表示對所有的感興趣.后者指出這個注解處理器可以處理哪些版本的 Java 代碼.
每個注解處理器在運行的時候都是單例的.如果不需要改變生成語法樹的內容, process() 方法就可以返回一個值為 false 的布爾值,通知編譯器這個 round 中得代碼未發生變化, 無需構造新的 JavaCompiler 實例,在這里只對程序命名進行檢查 , 不需要改變語法樹的內容, 因此process() 方法的返回值都是 false
實例如下:
AbstractProcessor
packageannotation.processing;importjava.util.EnumSet;importjava.util.Set;importjavax.annotation.processing.AbstractProcessor;importjavax.annotation.processing.Messager;importjavax.annotation.processing.ProcessingEnvironment;importjavax.annotation.processing.RoundEnvironment;importjavax.annotation.processing.SupportedAnnotationTypes;importjavax.annotation.processing.SupportedSourceVersion;importjavax.lang.model.SourceVersion;importjavax.lang.model.element.Element;importjavax.lang.model.element.ElementKind;importjavax.lang.model.element.ExecutableElement;importjavax.lang.model.element.Name;importjavax.lang.model.element.TypeElement;importjavax.lang.model.element.VariableElement;importjavax.lang.model.util.ElementScanner6;importjavax.tools.Diagnostic.Kind;//使用*表示支持所有的Annotations/*** 以下代碼出自 《深入理解Java虛擬機:JVM高級特性與最佳實踐》
**/@SupportedAnnotationTypes("*")//表示只對 JDK 1.6 的 Java 源碼感興趣
@SupportedSourceVersion(value =SourceVersion.RELEASE_6)public class NameCheckProcessor extendsAbstractProcessor {
@Overridepublic synchronized voidinit(ProcessingEnvironment processingEnv) {super.init(processingEnv);this.nameCheck = newNameCheck(processingEnv);
}privateNameCheck nameCheck;
@Overridepublic boolean process(Set extends TypeElement>annotations,
RoundEnvironment roundEnv) {if (!roundEnv.processingOver()) {for(Element element : roundEnv.getRootElements()) {
nameCheck.check(element);
}
}return false;
}/*** 程序名稱規范的編譯器插件 如果程序命名不合規范,將會輸出一個編譯器的Warning信息
*
*@authorkevin
**/
static classNameCheck {
Messager messager= null;publicNameCheckScanner nameCheckScanner;privateNameCheck(ProcessingEnvironment processingEnv) {
messager=processingEnv.getMessager();
nameCheckScanner= newNameCheckScanner(processingEnv);
}/*** 對Java程序明明進行檢查,根據《Java語言規范(第3版)》6.8節的要求,Java程序命名應當符合下列格式:
*
*
類或接口:符合駝式命名法,首字母大寫。*
方法:符合駝式命名法,首字母小寫。*
字段:*
*
類,實例變量:符合駝式命名法,首字母小寫。*
常量:要求全部大寫*
*
*
*@paramelement*/
public voidcheck(Element element) {
nameCheckScanner.scan(element);
}/*** 名稱檢查器實現類,繼承了1.6中新提供的ElementScanner6
* 將會以Visitor模式訪問抽象語法數中得元素
*
**/
static class NameCheckScanner extends ElementScanner6{
Messager messager= null;publicNameCheckScanner(ProcessingEnvironment processingEnv) {this.messager =processingEnv.getMessager();
}/*** 此方法用于檢查Java類*/@OverridepublicVoid visitType(TypeElement e, Void p) {
scan(e.getTypeParameters(), p);
checkCamelCase(e,true);super.visitType(e, p);return null;
}/*** 檢查傳入的Element是否符合駝式命名法,如果不符合,則輸出警告信息
*
*@parame
*@paramb*/
private void checkCamelCase(Element e, booleaninitialCaps) {
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+ "應當符合駝式命名法(Camel Case Names)", e);
}
}/*** 檢查方法命名是否合法*/@OverridepublicVoid 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;
}/*** 檢查變量是否合法*/@OverridepublicVoid visitVariable(VariableElement e, Void p) {/*如果這個Variable是枚舉或常量,則按大寫命名檢查,否則按照駝式命名法規則檢查*/
if (e.getKind() ==ElementKind.ENUM_CONSTANT|| e.getConstantValue() != null
||heuristicallyConstant(e)) {
checkAllCaps(e);
}else{
checkCamelCase(e,false);
}super.visitVariable(e, p);return null;
}/*** 大寫命名檢查,要求第一個字符必須是大寫的英文字母,其余部分可以下劃線或大寫字母
*
*@parame*/
private voidcheckAllCaps(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 == (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(Kind.WARNING,"常量:" +name+ " 應該全部以大寫字母" + "或下劃線命名,并且以字符開頭", e);
}
}/*** 判斷一個變量是否是常量
*
*@parame
*@return
*/
private booleanheuristicallyConstant(VariableElement e) {if (e.getEnclosingElement().getKind() ==ElementKind.INTERFACE) {return true;
}else if (e.getKind() ==ElementKind.FIELD&&e.getModifiers()
.containsAll(
EnumSet.of(
javax.lang.model.element.Modifier.FINAL,
javax.lang.model.element.Modifier.STATIC,
javax.lang.model.element.Modifier.PUBLIC))) {return true;
}return false;
}
}
}
}
測試代碼:
BADLY_NAMED_CODE
packageannotation.processing;public classBADLY_NAMED_CODE {enumColors {
Red, Blue, Green;
}static final int FORTY_TWO =42;public static int NOT_A_CONSTANT =FORTY_TWO;protected voidBadly_Named_Code() {return;
}public voidNOTcamelCASEmethodNAME() {return;
}
}
執行過程如下:
bogon:Desktop mjorcen$ javac annotation/processing/BADLY_NAMED_CODE.java
bogon:Desktop mjorcen$ javac annotation/processing/NameCheckProcessor.java
bogon:Desktop mjorcen$ javac-processor annotation.processing.NameCheckProcessor annotation/processing/BADLY_NAMED_CODE.java
警告: 來自注釋處理程序'annotation.processing.NameCheckProcessor' 的受支持 source 版本 'RELEASE_6' 低于 -source '1.7'annotation/processing/BADLY_NAMED_CODE.java:2: 警告: 名稱:BADLY_NAMED_CODE應當符合駝式命名法(Camel Case Names)public classBADLY_NAMED_CODE {^annotation/processing/BADLY_NAMED_CODE.java:5: 警告: 常量:Red 應該全部以大寫字母或下劃線命名,并且以字符開頭
Red, Blue, Green;^annotation/processing/BADLY_NAMED_CODE.java:5: 警告: 常量:Blue 應該全部以大寫字母或下劃線命名,并且以字符開頭
Red, Blue, Green;^annotation/processing/BADLY_NAMED_CODE.java:5: 警告: 常量:Green 應該全部以大寫字母或下劃線命名,并且以字符開頭
Red, Blue, Green;^annotation/processing/BADLY_NAMED_CODE.java:9: 警告: 名稱:NOT_A_CONSTANT 應當以小寫字母開頭public static int NOT_A_CONSTANT =FORTY_TWO;^
6 個警告
....
以上內容出自:
《深入理解Java虛擬機:JVM高級特性與最佳實踐》
將這個處理器注冊到 Eclipse 上,我建立如下 META-INF 文件:
META-INF/services/javax.annotation.processing.Processor:
annotation.processing.NameCheckProcessor
這里只包含了處理器實現類的類名。我不確定你是否可以在這里列出多個處理器。
就這樣。現在導出一個 jar 文件,并且在你需要用到這個處理器的工程上導入這個文件。
第二步:建立一個使用你的處理器的工程
In the properties for your new project go to?Java Compiler -> Annotation Processing
Check the?“Enable Project Specific Settings”?and make sure?“Enable annotation processing”?is checked. I also changed the generated source directory to a name which didn’t start with a dot so it wouldn’t be hidden in the package explorer (files or directories which start with a dot are by default filtered away in eclipse).
在工程的屬性中找到??Java Compiler -> Annotation Processing查看?“Enable Project Specific Settings”?確認?“Enable annotation processing”?被選中。為了不讓他在包瀏覽器中隱藏,我還修改了??generated source directory?,去掉了開始的點(Eclipse 會將文件名以點開始的文件或文件夾過濾掉)。
然后,轉到??Java Compiler -> Annotation Processing -> Factory Path你可以在這里導入處理器的 jar 文件。不可以使用工程引用。
點擊?“Advanced”?按鈕,會顯示一個對話框,列出了??META-INF/services/javax.annotation.processing.Processor?文件中的內容。選擇它并按OK。
第三步:Build!
完成了。這是在我的工程里顯示的樣子:
總結
以上是生活随笔為你收集整理的java编译器代码检查_java 命名代码检查-注解处理器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java okhttp https_Ok
- 下一篇: java web教学大纲_《JAVAWE