java 命名代码检查-注解处理器

命名代码检查

  根据 <Java 语言规范 (第 3 版) > 中第 6.8 节的要求, Java 程序命名应当符合下列格式的书写规范:

  1. 类 (或接口) : 符合驼式命名法, 首字母大写.
  2. 方法 : 符合驼式命名法, 首字母小写
  3. 字段 :
    1. 类或实例变量 : 符合驼式命名法 , 首字母小写
    2. 常量 : 要求全部有大写字母或下划线构成, 并且第一个字符不能是下划线.

 

  要通过注解处理器的 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
package annotation.processing;

import java.util.EnumSet;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
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.ElementKind;
import javax.lang.model.element.ExecutableElement;
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;

// 使用 * 表示支持所有的 Annotations
/**

  • 以下代码出自 《深入理解 Java 虚拟机:JVM 高级特性与最佳实践》

/
@SupportedAnnotationTypes(
"
")
// 表示只对 JDK 1.6 的 Java 源码感兴趣
@SupportedSourceVersion(value = SourceVersion.RELEASE_6)
public class NameCheckProcessor extends AbstractProcessor {
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.nameCheck = new NameCheck(processingEnv);
}

</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> NameCheck nameCheck;

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> process(Set&lt;? <span style="color: rgba(0, 0, 255, 1)">extends</span> TypeElement&gt;<span style="color: rgba(0, 0, 0, 1)"> annotations,
        RoundEnvironment roundEnv) {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">roundEnv.processingOver()) {
        </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Element element : roundEnv.getRootElements()) {
            nameCheck.check(element);
        }
    }
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
}

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 程序名称规范的编译器插件 如果程序命名不合规范,将会输出一个编译器的Warning信息
 * 
 * </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> kevin
 * 
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> NameCheck {
    Messager messager </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> NameCheckScanner nameCheckScanner;

    </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> NameCheck(ProcessingEnvironment processingEnv) {
        messager </span>=<span style="color: rgba(0, 0, 0, 1)"> processingEnv.getMessager();
        nameCheckScanner </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> NameCheckScanner(processingEnv);
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
     * 对Java程序明明进行检查,根据《Java语言规范(第3版)》6.8节的要求,Java程序命名应当符合下列格式:
     * &lt;ul&gt;
     * &lt;li&gt;类或接口:符合驼式命名法,首字母大写。
     * &lt;li&gt;方法:符合驼式命名法,首字母小写。
     * &lt;li&gt;字段:
     * &lt;ul&gt;
     * &lt;li&gt;类,实例变量:符合驼式命名法,首字母小写。
     * &lt;li&gt;常量:要求全部大写
     * &lt;/ul&gt;
     * &lt;/ul&gt;
     * 
     * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> element
     </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> check(Element element) {
        nameCheckScanner.scan(element);
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
     * 名称检查器实现类,继承了1.6中新提供的ElementScanner6&lt;br&gt;
     * 将会以Visitor模式访问抽象语法数中得元素
     * 
     * 
     </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">class</span> NameCheckScanner <span style="color: rgba(0, 0, 255, 1)">extends</span> ElementScanner6&lt;Void, Void&gt;<span style="color: rgba(0, 0, 0, 1)"> {
        Messager messager </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;

        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> NameCheckScanner(ProcessingEnvironment processingEnv) {
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.messager =<span style="color: rgba(0, 0, 0, 1)"> processingEnv.getMessager();
        }

        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 此方法用于检查Java类
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Void visitType(TypeElement e, Void p) {
            scan(e.getTypeParameters(), p);
            checkCamelCase(e, </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.visitType(e, p);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
        }

        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 检查传入的Element是否符合驼式命名法,如果不符合,则输出警告信息
         * 
         * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> e
         * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> b
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
        <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> checkCamelCase(Element e, <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> initialCaps) {
            String name </span>=<span style="color: rgba(0, 0, 0, 1)"> e.getSimpleName().toString();
            </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> previousUpper = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> conventional = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">int</span> firstCodePoint = name.codePointAt(0<span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (Character.isUpperCase(firstCodePoint)) {
                previousUpper </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">initialCaps) {
                    messager.printMessage(Kind.WARNING, </span>"名称:" +<span style="color: rgba(0, 0, 0, 1)"> name
                            </span>+ " 应当以小写字母开头"<span style="color: rgba(0, 0, 0, 1)">, e);
                    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
                }
            } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (Character.isLowerCase(firstCodePoint)) {
                </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (initialCaps) {
                    messager.printMessage(Kind.WARNING, </span>"名称:" +<span style="color: rgba(0, 0, 0, 1)"> name
                            </span>+ " 应当以大写字母开头"<span style="color: rgba(0, 0, 0, 1)">, e);
                    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
                }
            } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                conventional </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
            }
            </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (conventional) {
                </span><span style="color: rgba(0, 0, 255, 1)">int</span> cp =<span style="color: rgba(0, 0, 0, 1)"> firstCodePoint;
                </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = Character.charCount(cp); i &lt; name.length(); i +=<span style="color: rgba(0, 0, 0, 1)"> Character
                        .charCount(cp)) {
                    cp </span>=<span style="color: rgba(0, 0, 0, 1)"> name.codePointAt(i);
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (Character.isUpperCase(cp)) {
                        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (previousUpper) {
                            conventional </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
                            </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                        }
                        previousUpper </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
                    } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                        previousUpper </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
                    }
                }
            }
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">conventional) {
                messager.printMessage(Kind.WARNING, </span>"名称:" +<span style="color: rgba(0, 0, 0, 1)"> name
                        </span>+ "应当符合驼式命名法(Camel Case Names)"<span style="color: rgba(0, 0, 0, 1)">, e);
            }
        }

        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 检查方法命名是否合法
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Void visitExecutable(ExecutableElement e, Void p) {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (e.getKind() ==<span style="color: rgba(0, 0, 0, 1)"> ElementKind.METHOD) {
                Name name </span>=<span style="color: rgba(0, 0, 0, 1)"> e.getSimpleName();
                </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (name.contentEquals(e.getEnclosingElement()
                        .getSimpleName())) {
                    messager.printMessage(Kind.WARNING, </span>"一个普通方法:" +<span style="color: rgba(0, 0, 0, 1)"> name
                            </span>+ " 不应当与类名重复,避免与构造函数产生混淆"<span style="color: rgba(0, 0, 0, 1)">, e);
                    checkCamelCase(e, </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
                }
            }
            </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.visitExecutable(e, p);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
        }

        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 检查变量是否合法
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Void visitVariable(VariableElement e, Void p) {
            </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 如果这个Variable是枚举或常量,则按大写命名检查,否则按照驼式命名法规则检查 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
            <span style="color: rgba(0, 0, 255, 1)">if</span> (e.getKind() ==<span style="color: rgba(0, 0, 0, 1)"> ElementKind.ENUM_CONSTANT
                    </span>|| e.getConstantValue() != <span style="color: rgba(0, 0, 255, 1)">null</span>
                    ||<span style="color: rgba(0, 0, 0, 1)"> heuristicallyConstant(e)) {
                checkAllCaps(e);
            } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                checkCamelCase(e, </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
            }
            </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.visitVariable(e, p);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
        }

        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 大写命名检查,要求第一个字符必须是大写的英文字母,其余部分可以下划线或大写字母
         * 
         * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> e
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
        <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> checkAllCaps(VariableElement e) {
            String name </span>=<span style="color: rgba(0, 0, 0, 1)"> e.getSimpleName().toString();
            </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> conventional = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">int</span> firstCodePoint = name.codePointAt(0<span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">Character.isUpperCase(firstCodePoint)) {
                conventional </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
            } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> previousUnderscore = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
                </span><span style="color: rgba(0, 0, 255, 1)">int</span> cp =<span style="color: rgba(0, 0, 0, 1)"> firstCodePoint;
                </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = Character.charCount(cp); i &lt; name.length(); i +=<span style="color: rgba(0, 0, 0, 1)"> Character
                        .charCount(cp)) {
                    cp </span>=<span style="color: rgba(0, 0, 0, 1)"> name.codePointAt(i);
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (cp == (<span style="color: rgba(0, 0, 255, 1)">int</span>) '_'<span style="color: rgba(0, 0, 0, 1)">) {
                        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (previousUnderscore) {
                            conventional </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
                            </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                        }
                        previousUnderscore </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
                    } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                        previousUnderscore </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
                        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">Character.isUpperCase(cp)
                                </span>&amp;&amp; !<span style="color: rgba(0, 0, 0, 1)">Character.isDigit(cp)) {
                            conventional </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
                            </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
                        }
                    }

                }
            }
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">conventional) {
                messager.printMessage(Kind.WARNING, </span>"常量:" +<span style="color: rgba(0, 0, 0, 1)"> name
                        </span>+ " 应该全部以大写字母" + "或下划线命名,并且以字符开头"<span style="color: rgba(0, 0, 0, 1)">, e);
            }
        }

        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 判断一个变量是否是常量
         * 
         * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> e
         * </span><span style="color: rgba(128, 128, 128, 1)">@return</span>
         <span style="color: rgba(0, 128, 0, 1)">*/</span>
        <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> heuristicallyConstant(VariableElement e) {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (e.getEnclosingElement().getKind() ==<span style="color: rgba(0, 0, 0, 1)"> ElementKind.INTERFACE) {
                </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
            } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (e.getKind() ==<span style="color: rgba(0, 0, 0, 1)"> ElementKind.FIELD
                    </span>&amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> e.getModifiers()
                            .containsAll(
                                    EnumSet.of(
                                            javax.lang.model.element.Modifier.FINAL,
                                            javax.lang.model.element.Modifier.STATIC,
                                            javax.lang.model.element.Modifier.PUBLIC))) {
                </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
        }
    }
}

}

测试代码: 

BADLY_NAMED_CODE
package annotation.processing;
public class BADLY_NAMED_CODE {
</span><span style="color: rgba(0, 0, 255, 1)">enum</span><span style="color: rgba(0, 0, 0, 1)"> Colors {
    Red, Blue, Green;
}
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">int</span> FORTY_TWO =42<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span> NOT_A_CONSTANT =<span style="color: rgba(0, 0, 0, 1)"> FORTY_TWO;

</span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Badly_Named_Code() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> NOTcamelCASEmethodNAME() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}

}

执行过程如下:

  

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 class BADLY_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!

    完成了。这是在我的工程里显示的样子: