zoukankan      html  css  js  c++  java
  • Java中的APT的工作过程

    Java中的APT的工作过程

    APT即Annotatino Processing Tool, 他的作用是处理代码中的注解, 用来生成代码, 换句话说, 这是用代码生成代码的工具, 减少boilerplate代码.

    我们通过一个简单的例子来简单APT的工作过程, 因为本文demo不设计ide及gradle等, 请注意包名及import问题.

    根据上一篇博客Java中的自定义注解, 首先设计一个自定义注解MyAnnotation.

    package com.example;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.SOURCE) // 只保留到编译阶段
    @Target(ElementType.TYPE) // 可用于类, 接口..
    public @interface MyAnnotation {
    }
    

    下面来看一下我们的主角, Processor:

    package com.example;
    
    import javax.annotation.processing.AbstractProcessor;
    import javax.annotation.processing.ProcessingEnvironment;
    import javax.annotation.processing.RoundEnvironment;
    import javax.lang.model.SourceVersion;
    import javax.lang.model.element.TypeElement;
    import java.util.HashSet;
    import java.util.Set;
    
    public class MyProcessor extends AbstractProcessor {
    
        // Processor初始化回调
        @Override
        public synchronized void init(ProcessingEnvironment processingEnv) {
            super.init(processingEnv);
            System.out.println("MyProcessor init"); 
        }
    
        // processor处理过程的回调, 如果需要生成代码, 就在这个方法中写. 这个demo暂时不演示代码生成.
        @Override
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
            System.out.println("process");
            return false;
        }
    
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            // 在此处声明该processor支持的注解类型
            Set<String> set = new HashSet<>();
            set.add(MyAnnotation.class.getCanonicalName());
            return set;
        }
    
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return SourceVersion.latestSupported();
        }
    }
    
    

    那么我们如何把这个apt注册给javac呢? 我们将项目以常规的模式打包, 但是在META-INF目录中加入一个services文件夹, 在其中创建一个名为javax.annotation.processing.Processor的文件, 以文本将processor的完整名字写进去, 如果有多个processor, 换行即可.

    javax.annotation.processing.Processor的内容:

    com.example.MyProcessor
    

    最终jar包的结构:

    mp.jar // jar包名字随意起
        com
            example
                MyProcess.class
                MyAnnotation.class
        META-INF
            services
                javax.annotation.processing.Processor
            MANIFEST.MF
    
    

    测试

    测试的例子很简单:

    @MyAnnotation
    public class Sample {
        public static void main(String[] args) {
            System.out.printf("Hello, World!");
        }
    }
    

    我们用javac编译这个文件

    $ javac -cp mp.jar Sample.java
    MyProcessor init
    process
    process
    

    可以看到, 我们的Process已经生成了, 但是process过程输出了两次, 原因可以参考下图:

    process的过程会进行两边, 我们代码生成的过程应该在第一遍, 因为第二次processor的过程应当负责做一些清理的工作, 某些打包工具可能不会编译在第二阶段生成的.java源文件.

    if (!roundEnv.processingOver()) { ... }
    
  • 相关阅读:
    1.BMap(百度地图)第二次加载显示不全
    SpringMVC的拦截器
    装饰者模式
    java产生随机数
    VS 常用快捷键
    给包含compid列且值为null ,表的行数据赋值--
    遍历数据库,删除包含指定列的表的行数据-
    DataTable select根据条件取值
    临时表汇总金额
    Redirect url 路径简单介绍
  • 原文地址:https://www.cnblogs.com/fortitude/p/10936386.html
Copyright © 2011-2022 走看看