美文网首页
注解处理器->02源码注释

注解处理器->02源码注释

作者: 冉桓彬 | 来源:发表于2019-05-31 10:58 被阅读0次

    源码: https://blog.csdn.net/u013045971/article/details/53509237

    文档: https://www.jianshu.com/p/9177db78cfed

    注解处理器如果说难, 可能只是难在api上面, 由于对api的不熟, 而且网上也不太容易搜索相关的答案, 所以可能觉得难.
    切记:不要背api, 如果工作中涉及到需要自己去写相关代码, 只需要记得哪里有相关的实现, 然后直接复制粘贴拿来使用即可.
    下面对网上别人写的现成的demo进行注释, 完成之后打算进阶对ButterKnife以及ARouter注解处理器相关源码进行注释.

    一、AptActivity

    public class AptActivity extends Activity {
        @BindView(R.id.btn1)
        public Button btn1;
        @BindView(R.id.btn2)
        public Button btn2;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_apt);
            ButterKnife.bind(this);
            btn1.setText("按钮1");
            btn2.setText("按钮2");
        }
    
        @OnClick({R.id.btn1})
        public void click1() {
            Log.v("AndroidTest", "btn1-click");
        }
    
        @OnClick({R.id.btn2})
        public void click2() {
            Log.v("AndroidTest", "btn2-click");
        }
    }
    

    二、AptActivity$$Injector这段代码在查看AnnotatedClass代码时再来对照的查看

    public class AptActivity$$Injector implements Injector<AptActivity> {
        @Override
        public void inject(final AptActivity host, Object source, Finder finder) {
            host.btn1=(Button)finder.findView(source, 2131427463);
            host.btn2=(Button)finder.findView(source, 2131427464);
            View.OnClickListener listener;
            listener = new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    host.click1();
                }
            };
            finder.findView(source, 2131427463).setOnClickListener(listener);
            listener = new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    host.click2();
                }
            };
            finder.findView(source, 2131427464).setOnClickListener(listener);
        }
    }
    

    三、AbstractProcessor

    @AutoService(Processor.class)
    public class BindViewProcessor extends AbstractProcessor {
        // 文件相关的辅助类
        private Filer    filer;
        // 元素相关的辅助类
        private Elements elementUtils;
        // 日志相关的辅助类
        private Messager messager;
        // 解析的目标注解集合
        private Map<String, AnnotatedClass> annotatedClassMap = new HashMap<>();
        private Logger logger;
    
        // ProcessingEnvironment提供一系列的工具类
        @Override
        public synchronized void init(ProcessingEnvironment processingEnv) {
            super.init(processingEnv);
            // 作为工具类, 提供对应的Element.
            elementUtils = processingEnv.getElementUtils();
            // 用于编译时日志的输出.
            messager = processingEnv.getMessager();
            // 文件相关的辅助类, 后边生成对应的java文件时需要使用到.
            filer = processingEnv.getFiler();
            logger = new Logger(messager);
        }
    
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            logger.info("BindView.class.getCanonicalName():" + BindView.class.getCanonicalName());
            logger.info("OnClick.class.getCanonicalName():" + OnClick.class.getCanonicalName());
            Set<String> types = new LinkedHashSet<>();
            types.add(BindView.class.getCanonicalName());
            types.add(OnClick.class.getCanonicalName());
            return types;
        }
    
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return SourceVersion.latestSupported();
        }
        // RoundEnvironment: 运行环境, 通过该对象可以获取被指定注解标注的元素的集合.
        @Override
        public boolean process(Set<? extends TypeElement> anno, RoundEnvironment roundEnv) {
            annotatedClassMap.clear();
            try {
                // 获取被BindView注解的元素的集合.
                processBindView(roundEnv);
                // 获取被OnClick注解的元素的集合.
                processOnClick(roundEnv);
            } catch (IllegalArgumentException e) {
                return true;
            }
    
            try {
                for (AnnotatedClass annotatedClass : annotatedClassMap.values()) {
                    annotatedClass.setLogger(logger);
                    logger.info("annotatedClass:" + annotatedClass + "\nannotatedClass.getFullClassName():" + annotatedClass.getFullClassName());
                    JavaFile javaFile = annotatedClass.generateFinder();
                    // 这里添加打印然后查看javaFile输出的内容
                    logger.info("javaFile:" + javaFile + ",mFiler:" + filer);
                    javaFile.writeTo(filer);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }
    
        private void processBindView(RoundEnvironment roundEnv) {
            // 这里的元素集合就是AptActivity中的btn1与btn2对应的元素:VariableElement.
            for (Element element : roundEnv.getElementsAnnotatedWith(BindView.class)) {
                AnnotatedClass annotatedClass = getAnnotatedClass(element);
                BindViewField field = new BindViewField(element);
                logger.info("processBindView()---element:" + element + ",field:" + field);
                annotatedClass.addField(field);
            }
        }
    
        private AnnotatedClass getAnnotatedClass(Element element) {
            // 1.通过getEnclosingElement可以获取当前Element对应源代码中的父类型元素. 这里指的就是AptActivity
            //   对应的元素类型.
            // 2.只能通过TypeElement获取到对应的类名称, 但是不能获取类信息.
            // 3.如果需要获取类相关的信息, 可以通过typeElement.asType()获取对应的TypeMirror.
            TypeElement encloseElement = (TypeElement) element.getEnclosingElement();
            // 获取对应的类名称.
            String fullClassName = encloseElement.getQualifiedName().toString();
            // 一个fullClassName对应一个AnnotatedClass.
            AnnotatedClass annotatedClass = annotatedClassMap.get(fullClassName);
            if (annotatedClass == null) {
                annotatedClass = new AnnotatedClass(encloseElement, elementUtils);
                annotatedClassMap.put(fullClassName, annotatedClass);
            }
            return annotatedClass;
        }
    
        private void processOnClick(RoundEnvironment roundEnv) {
            // 这里的元素集合就是AptActivity中的click1()与click2()对应的元素:ExecuteableElement
            for (Element element : roundEnv.getElementsAnnotatedWith(OnClick.class)) {
                AnnotatedClass annotatedClass = getAnnotatedClass(element);
                OnClickMethod method = new OnClickMethod(element);
                annotatedClass.addMethod(method);
            }
        }
    }
    

    四、BindViewField

    public class BindViewField {
        // VariableElement:表示一个字段、enum常量、方法或构造方法参数、局部变量或异常参数.
        // BindView注解针对的就是变量, 所以这里会将传入的element强转为VariableElement.
        private VariableElement mFieldElement;
        // 获取对应View的id.
        private int mResId;
        public BindViewField(Element element) throws IllegalArgumentException {
            // 判断对应元素的类型是否为FIELD类型.
            if (element.getKind() != ElementKind.FIELD) {
                ...
            }
            mFieldElement = (VariableElement) element;
            BindView bindView = mFieldElement.getAnnotation(BindView.class);
            mResId = bindView.value();
        }
        // 获取被BindView注解的对象的变量名.
        public Name getFieldName() {
            return mFieldElement.getSimpleName();
        }
        public int getResId() {
            return mResId;
        }
        // 因为通过Element无法获取对应元素的具体信息, 所以需要通过asType获取对应的TypeMirror, 然后
        // 根据TypeMirror获取对应的元素信息.
        public TypeMirror getFieldType() {
            return mFieldElement.asType();
        }
    }
    

    五、OnClickMethod同BindViewField , 这里不再分析

    public class OnClickMethod {
        private Name methodName;
        public int[] ids;
        public OnClickMethod(Element element) {
            if (element.getKind() != ElementKind.METHOD) {
                throw new IllegalArgumentException(String.format("Only method can be annotated width @%s",
                        OnClick.class.getSimpleName()));
            }
            ExecutableElement methodElement = (ExecutableElement) element;
            methodName = methodElement.getSimpleName();
            ids = methodElement.getAnnotation(OnClick.class).value();
            if (ids == null) {
                throw new IllegalArgumentException(String.format("Must set valid ids for @%s", OnClick.class.getSimpleName()));
            } else {
                for (int id : ids) {
                    if (id < 0) {
                        throw new IllegalArgumentException(String.format("Must set valid ids for @%s", OnClick.class.getSimpleName()));
                    }
                }
            }
            List<? extends VariableElement> parameters = methodElement.getParameters();
            if (parameters.size() > 0) {
                throw new IllegalArgumentException(String.format("The method annotated with @%s must have no parameters", OnClick.class.getSimpleName()));
            }
        }
        public Name getMethodName() {
            return methodName;
        }
    }
    

    六、AnnotatedClass

    public class AnnotatedClass {
        // 类元素
        public TypeElement         mClassElement;
        // 成员变量: 持有btn1、btn2对应的BindViewField
        public List<BindViewField> mFiled;
        // 方法: 持有click1()、click2()对应的OnClickMethod
        public List<OnClickMethod> mMethod;
        // 元素帮助类
        public Elements            mElementUtils;
        // 在BindViewProcessor中可知, 一个fullClassName对应一个AnnotatedClass.
        public AnnotatedClass(TypeElement classElement, Elements elementUtils) {
            this.mClassElement = classElement;
            this.mElementUtils = elementUtils;
            this.mFiled = new ArrayList<>();
            this.mMethod = new ArrayList<>();
        }
    
        public String getFullClassName() {
            return mClassElement.getQualifiedName().toString();
        }
    
        public void addField(BindViewField field) {
            mFiled.add(field);
        }
    
        public void addMethod(OnClickMethod method) {
            mMethod.add(method);
        }
        // 生成对应的java文件
        public JavaFile generateFinder() {
            /***构建方法*/
            MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("inject") //方法名称
                    .addModifiers(Modifier.PUBLIC) // 方法访问权限
                    .addAnnotation(Override.class) // 方法的注解
                    .returns(TypeName.VOID) //方法的返回值
                    .addParameter(TypeName.get(mClassElement.asType()), "host", Modifier.FINAL) // 方法参数
                    .addParameter(TypeName.OBJECT, "source") // 方法参数
                    .addParameter(TypeUtil.FINDER, "finder"); // 方法参数
            /*** 遍历添加类成员*/
            for (BindViewField field : mFiled) {
                logger.info("field.getFieldName:" + field.getFieldName() + ", field.getFieldType:" + field.getFieldType());
                // methodBuilder方法内部的执行语句
                methodBuilder.addStatement("host.$N=($T)finder.findView(source,$L)",
                        field.getFieldName(),
                        ClassName.get(field.getFieldType()),
                        field.getResId());
            }
            /*** 声明Listener*/
            if (mMethod.size() > 0) {
                logger.info("TypeUtil.ONCLICK_LISTENER:" + TypeUtil.ONCLICK_LISTENER);
                // methodBuilder方法内部的执行语句
                methodBuilder.addStatement("$T listener", TypeUtil.ONCLICK_LISTENER);
            }
    
            for (OnClickMethod method : mMethod) {// click1()、click2()
                TypeSpec listener = TypeSpec.anonymousClassBuilder("")
                        // 为当前Listener添加父类或者父接口, 这里使用的是匿名内部类的方式
                        .addSuperinterface(TypeUtil.ONCLICK_LISTENER)
                        .addMethod(MethodSpec.methodBuilder("onClick") // 定义方法名
                                .addAnnotation(Override.class) // 定义方法的继承关系
                                .addModifiers(Modifier.PUBLIC) // 定义方法的访问权限
                                .returns(TypeName.VOID) // 定义方法的返回值
                                .addParameter(TypeUtil.ANDROID_VIEW, "view") // 定义方法的参数
                                .addStatement("host.$N()", method.getMethodName()) // 定义方法内部的语句
                                .build())
                        .build();
                methodBuilder.addStatement("listener = $L ", listener);
                for (int id : method.ids) {
                    methodBuilder.addStatement("finder.findView(source,$L).setOnClickListener(listener)", id);
                }
            }
            // 定义包名
            String packageName = getPackageName(mClassElement);
            // 定义类名
            String className = getClassName(mClassElement, packageName);
            ClassName bindClassName = ClassName.get(packageName, className);
            /*** 构建类*/
            TypeSpec finderClass = TypeSpec.classBuilder(bindClassName.simpleName() + "$$Injector")
                    .addModifiers(Modifier.PUBLIC) // 定义类的访问权限
                    // 为当前类添加父类或者父接口
                    .addSuperinterface(ParameterizedTypeName.get(TypeUtil.INJECTOR, TypeName.get(mClassElement.asType())))
                    .addMethod(methodBuilder.build())  // 将methodBuilder添加到类中
                    .build();
            // 构建对应的java文件, 但是此时还没有生成对应的java文件
            return JavaFile.builder(packageName, finderClass).build();
        }
    
        public String getPackageName(TypeElement type) {
            return mElementUtils.getPackageOf(type).getQualifiedName().toString();
        }
    
        private static String getClassName(TypeElement type, String packageName) {
            int packageLen = packageName.length() + 1;
            return type.getQualifiedName().toString().substring(packageLen).replace('.', '$');
        }
    
        private Logger logger;
    
        public void setLogger(Logger logger) {
            this.logger = logger;
        }
    }
    

    六、Logger

    public class Logger {
        private Messager messager;
        public Logger(Messager messager) {
            this.messager = messager;
        }
        public void info(String info) {
            if (messager == null) {
                return;
            }
            messager.printMessage(Diagnostic.Kind.NOTE, info);
        }
    }
    

    相关文章

      网友评论

          本文标题:注解处理器->02源码注释

          本文链接:https://www.haomeiwen.com/subject/scbvtctx.html