插入式注解处理器

通过Javac命令的 -processor 参数来执行编译时需要附带的注解处理器,如果有多个注解处理器的话,用逗号分隔。

还可以使用-XprintRounds和-XprintProcessorInfo参数来查看注解处理器运作的详细信息。

NameCheckProcessor的实例只演示了JSR-269嵌入式注解处理API其中的一部分功能,基于这组API支持的项目还有用于效验Hibernate标签使用正确性的Hibernate Validator Annotation Processor(本质上与NameCheckProcessor所做的事情差不多),自动为字段生成getter和setter方法的Project Lombok(根据已有元素生成新的语法树元素)等,

 代码如下:

[java]  view plain copy
  1. import java.util.EnumSet;  
  2. import java.util.Set;  
  3.   
  4. import javax.annotation.processing.AbstractProcessor;  
  5. import javax.annotation.processing.Messager;  
  6. import javax.annotation.processing.ProcessingEnvironment;  
  7. import javax.annotation.processing.RoundEnvironment;  
  8. import javax.annotation.processing.SupportedAnnotationTypes;  
  9. import javax.annotation.processing.SupportedSourceVersion;  
  10. import javax.lang.model.SourceVersion;  
  11. import javax.lang.model.element.Element;  
  12. import javax.lang.model.element.ElementKind;  
  13. import javax.lang.model.element.ExecutableElement;  
  14. import javax.lang.model.element.Name;  
  15. import javax.lang.model.element.TypeElement;  
  16. import javax.lang.model.element.VariableElement;  
  17. import javax.lang.model.util.ElementScanner7;  
  18. import javax.tools.Diagnostic.Kind;  
  19. /** 
  20.  * javac NameCheckProcessor.java 
  21.  * javac -processor NameCheckProcessor FT.java 
  22.  * @author kevin 
  23.  * 
  24.  */  
  25.   
  26.   
  27. //使用*表示支持所有的Annotations   
  28. @SupportedAnnotationTypes(value = "*")  
  29. @SupportedSourceVersion(value = SourceVersion.RELEASE_7)  
  30. public class NameCheckProcessor extends AbstractProcessor {  
  31.     @Override  
  32.     public synchronized void init(ProcessingEnvironment processingEnv) {  
  33.         super.init(processingEnv);  
  34.         this.nameCheck = new NameCheck(processingEnv);  
  35.     }  
  36.   
  37.     private NameCheck nameCheck;  
  38.   
  39.     @Override  
  40.     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {  
  41.         if (!roundEnv.processingOver()) {  
  42.             for (Element element : roundEnv.getRootElements()) {  
  43.                 nameCheck.check(element);  
  44.             }  
  45.         }  
  46.         return false;  
  47.     }  
  48.   
  49.     /** 
  50.      * 程序名称规范的编译器插件 如果程序命名不合规范,将会输出一个编译器的Warning信息 
  51.      *  
  52.      * @author kevin 
  53.      *  
  54.      */  
  55.     public static class NameCheck {  
  56.         Messager messager = null;  
  57.         public NameCheckScanner nameCheckScanner;  
  58.   
  59.         private NameCheck(ProcessingEnvironment processingEnv) {  
  60.             messager = processingEnv.getMessager();  
  61.             nameCheckScanner = new NameCheckScanner(processingEnv);  
  62.         }  
  63.   
  64.         /** 
  65.          * 对Java程序明明进行检查,根据《Java语言规范(第3版)》6.8节的要求,Java程序命名应当符合下列格式: 
  66.          * <ul> 
  67.          * <li>类或接口:符合驼式命名法,首字母大写。 
  68.          * <li>方法:符合驼式命名法,首字母小写。 
  69.          * <li>字段: 
  70.          * <ul> 
  71.          * <li>类,实例变量:符合驼式命名法,首字母小写。 
  72.          * <li>常量:要求全部大写 
  73.          * </ul> 
  74.          * </ul> 
  75.          *  
  76.          * @param element 
  77.          */  
  78.         public void check(Element element) {  
  79.             nameCheckScanner.scan(element);  
  80.         }  
  81.   
  82.         /** 
  83.          * 名称检查器实现类,继承了1.6中新提供的ElementScanner6<br> 
  84.          * 将会以Visitor模式访问抽象语法数中得元素 
  85.          *  
  86.          * @author kevin 
  87.          *  
  88.          */  
  89.         public static class NameCheckScanner extends ElementScanner7<Void, Void> {  
  90.             Messager messager = null;  
  91.   
  92.             public NameCheckScanner(ProcessingEnvironment processingEnv) {  
  93.                 this.messager = processingEnv.getMessager();  
  94.             }  
  95.   
  96.             /** 
  97.              * 此方法用于检查Java类 
  98.              */  
  99.             @Override  
  100.             public Void visitType(TypeElement e, Void p) {  
  101.                 scan(e.getTypeParameters(), p);  
  102.                 checkCamelCase(e, true);  
  103.                 super.visitType(e, p);  
  104.                 return null;  
  105.             }  
  106.   
  107.             /** 
  108.              * 检查传入的Element是否符合驼式命名法,如果不符合,则输出警告信息 
  109.              *  
  110.              * @param e 
  111.              * @param b 
  112.              */  
  113.             private void checkCamelCase(Element e, boolean initialCaps) {  
  114.                 String name = e.getSimpleName().toString();  
  115.                 boolean previousUpper = false;  
  116.                 boolean conventional = true;  
  117.                 int firstCodePoint = name.codePointAt(0);  
  118.                 if (Character.isUpperCase(firstCodePoint)) {  
  119.                     previousUpper = true;  
  120.                     if (!initialCaps) {  
  121.                         messager.printMessage(Kind.WARNING, "名称:" + name + " 应当已小写字符开头", e);  
  122.                         return;  
  123.                     }  
  124.                 } else if (Character.isLowerCase(firstCodePoint)) {  
  125.                     if (initialCaps) {  
  126.                         messager.printMessage(Kind.WARNING, "名称:" + name + " 应当已大写字母开否", e);  
  127.                         return;  
  128.                     }  
  129.                 } else {  
  130.                     conventional = false;  
  131.                 }  
  132.                 if (conventional) {  
  133.                     int cp = firstCodePoint;  
  134.                     for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {  
  135.                         cp = name.codePointAt(i);  
  136.                         if (Character.isUpperCase(cp)) {  
  137.                             if (previousUpper) {  
  138.                                 conventional = false;  
  139.                                 break;  
  140.                             }  
  141.                             previousUpper = true;  
  142.                         } else {  
  143.                             previousUpper = false;  
  144.                         }  
  145.                     }  
  146.                 }  
  147.                 if (!conventional) {  
  148.                     messager.printMessage(Kind.WARNING, "名称:" + name + "应当符合驼式命名法(Camel Case Names)", e);  
  149.                 }  
  150.             }  
  151.   
  152.             /** 
  153.              * 检查方法命名是否合法 
  154.              */  
  155.             @Override  
  156.             public Void visitExecutable(ExecutableElement e, Void p) {  
  157.                 if (e.getKind() == ElementKind.METHOD) {  
  158.                     Name name = e.getSimpleName();  
  159.                     if (name.contentEquals(e.getEnclosingElement().getSimpleName())) {  
  160.                         messager.printMessage(Kind.WARNING, "一个普通方法:" + name + " 不应当与类名重复,避免与构造函数产生混淆", e);  
  161.                         checkCamelCase(e, false);  
  162.                     }  
  163.                 }  
  164.                 super.visitExecutable(e, p);  
  165.                 return null;  
  166.             }  
  167.   
  168.             /** 
  169.              * 检查变量是否合法 
  170.              */  
  171.             @Override  
  172.             public Void visitVariable(VariableElement e, Void p) {  
  173.                 /* 如果这个Variable是枚举或常量,则按大写命名检查,否则按照驼式命名法规则检查 */  
  174.                 if (e.getKind() == ElementKind.ENUM_CONSTANT || e.getConstantValue() != null || heuristicallyConstant(e)) {  
  175.                     checkAllCaps(e);  
  176.                 } else {  
  177.                     checkCamelCase(e, false);  
  178.                 }  
  179.                 super.visitVariable(e, p);  
  180.                 return null;  
  181.             }  
  182.   
  183.             /** 
  184.              * 大写命名检查,要求第一个字符必须是大写的英文字母,其余部分可以下划线或大写字母 
  185.              *  
  186.              * @param e 
  187.              */  
  188.             private void checkAllCaps(VariableElement e) {  
  189.                 String name = e.getSimpleName().toString();  
  190.                 boolean conventional = true;  
  191.                 int firstCodePoint = name.codePointAt(0);  
  192.                 if (!Character.isUpperCase(firstCodePoint)) {  
  193.                     conventional = false;  
  194.                 } else {  
  195.                     boolean previousUnderscore = false;  
  196.                     int cp = firstCodePoint;  
  197.                     for (int i = Character.charCount(cp); i < name.length(); i += Character.charCount(cp)) {  
  198.                         cp = name.codePointAt(i);  
  199.                         if (cp == (int'_') {  
  200.                             if (previousUnderscore) {  
  201.                                 conventional = false;  
  202.                                 break;  
  203.                             }  
  204.                             previousUnderscore = true;  
  205.                         } else {  
  206.                             previousUnderscore = false;  
  207.                             if (!Character.isUpperCase(cp) && !Character.isDigit(cp)) {  
  208.                                 conventional = false;  
  209.                                 break;  
  210.                             }  
  211.                         }  
  212.   
  213.                     }  
  214.                 }  
  215.                 if (!conventional) {  
  216.                     messager.printMessage(Kind.WARNING, "常量:" + name + " 应该全部以大写字母" + "或下划线命名,并且以字符开否", e);  
  217.                 }  
  218.             }  
  219.   
  220.             /** 
  221.              * 判断一个变量是否是常量 
  222.              *  
  223.              * @param e 
  224.              * @return 
  225.              */  
  226.             private boolean heuristicallyConstant(VariableElement e) {  
  227.                 if (e.getEnclosingElement().getKind() == ElementKind.INTERFACE) {  
  228.                     return true;  
  229.                 } 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))) {  
  230.                     return true;  
  231.                 }  
  232.                 return false;  
  233.             }  
  234.         }  
  235.     }  
  236.   
  237. }  

在写一个测试类:

[java]  view plain copy
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. public class FT {  
  5.     public static class A_B_C {  
  6.   
  7.     }  
  8.     public static String ab_sd="";  
  9.     public static int method(List<Integer> list) {  
  10.         System.out.println("method(List<Integer>list)");  
  11.         return 1;  
  12.     }  
  13.   
  14.     public static void main(String[] args) {  
  15.         method(new ArrayList<Integer>());  
  16.         Long aLong = 2l;  
  17.         Integer aInteger = 1;  
  18.         Integer bInteger = 1;  
  19.         System.out.println(aLong.equals(aInteger + bInteger));  
  20.         System.out.println(aInteger.equals(1L));  
  21.         System.out.println("true");  
  22.     }  
  23. }  

接下来让我们进入到命令行试试

javac NameCheckProcessor.java 

javac -processor NameCheckProcessor FT.java

FT.java:4: 警告: 名称:FT应当符合驼式命名法(Camel Case Names)

public class FT {

       ^

1 个警告

你可能感兴趣的:(插入式注解处理器)