美文网首页
Annotation Processor使用实例

Annotation Processor使用实例

作者: 过往不恋纵情向前 | 来源:发表于2019-03-20 11:07 被阅读0次

    概念

    注解处理器(Annotation Processeor)是java内置的注解处理工具。它可以在代码编译阶段通过扫描代码源码读取代码中的注解。换句话说我们可以利用它在代码编译阶段扫描源码中的注解(Annotation)动态生成一些java文件,让机器帮助我们生成大量重复代码,提高工作效率。

    使用方式

    实例

    以下代码帮助我们根据源码中的Scene注解里声明的SceneId自动生成SceneIds.java文件,达到给场景起别名的目的。下边的例子包括了注解处理器(Annotation Processeor)的使用、注解配置、代码生等功能。

    代码

    SceneProcessor.java
    package com.hyena.framework.processor;
    
    import com.google.auto.service.AutoService;
    import com.hyena.framework.annotation.Scene;
    import com.squareup.javapoet.FieldSpec;
    import com.squareup.javapoet.JavaFile;
    import com.squareup.javapoet.MethodSpec;
    import com.squareup.javapoet.TypeSpec;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import javax.annotation.processing.AbstractProcessor;
    import javax.annotation.processing.Filer;
    import javax.annotation.processing.Messager;
    import javax.annotation.processing.ProcessingEnvironment;
    import javax.annotation.processing.Processor;
    import javax.annotation.processing.RoundEnvironment;
    import javax.lang.model.SourceVersion;
    import javax.lang.model.element.Element;
    import javax.lang.model.element.Modifier;
    import javax.lang.model.element.TypeElement;
    import javax.lang.model.util.Elements;
    import javax.tools.Diagnostic;
    
    /**
     * Created by yangzc on 17/11/23.
     */
    @AutoService(Processor.class)
    public class SceneProcessor extends AbstractProcessor {
    
        private static final String APPLICATION_ID = "applicationId";
    
        private Filer filer;
        private Elements elementUtils;
        private Messager messager;
    
        private String applicationId = "com.hyena.ids";
        private HashMap<String, String> mSceneMap = new HashMap<>();
    
        @Override
        public synchronized void init(ProcessingEnvironment processingEnvironment) {
            super.init(processingEnvironment);
            this.filer = processingEnvironment.getFiler();
            this.elementUtils = processingEnvironment.getElementUtils();
            this.messager = processingEnvironment.getMessager();
    
            if (processingEnvironment.getOptions() != null) {
                Map<String, String> options = processingEnvironment.getOptions();
                String applicationId = options.get(APPLICATION_ID);
                if (applicationId != null && !"".equals(applicationId)) {
                    this.applicationId = applicationId;
                    messager.printMessage(Diagnostic.Kind.NOTE, "applicationId: " + applicationId);
                }
            }
        }
    
        @Override
        public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
            if (roundEnv.getRootElements().isEmpty() || isIgnore(roundEnv)) {
                return true;
            }
            messager.printMessage(Diagnostic.Kind.NOTE, "process!!!");
            mSceneMap.clear();
            for (Element e : roundEnv.getElementsAnnotatedWith(Scene.class)) {
                Scene scene = e.getAnnotation(Scene.class);
                mSceneMap.put(scene.value(), e.toString());
            }
            TypeSpec.Builder javaClassBuilder = TypeSpec.classBuilder("SceneIds").addModifiers(Modifier.PUBLIC);
            List<String> methodLine = new ArrayList();
            if (!mSceneMap.isEmpty()) {
                //添加静态变量
                Iterator<String> iterator = mSceneMap.keySet().iterator();
                while (iterator.hasNext()) {
                    String sceneId = iterator.next();
                    String className = mSceneMap.get(sceneId);
                    FieldSpec fieldSpec = FieldSpec.builder(String.class, sceneId)
                            .addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC)
                            .initializer("$S", sceneId).build();
                    javaClassBuilder.addField(fieldSpec);
                    methodLine.add("sceneMap.put(" + sceneId + ", \"" + className + "\")");
                }
            }
    
            //添加getSceneMaps方法
            MethodSpec.Builder methodGetSceneMapSpecBuild = MethodSpec.methodBuilder("getSceneMaps")
                    .returns(HashMap.class)
                    .addModifiers(Modifier.STATIC, Modifier.PUBLIC)
                    .addStatement("$T sceneMap = new $T()", HashMap.class, HashMap.class);
            for (int i = 0; i < methodLine.size(); i++) {
                methodGetSceneMapSpecBuild.addStatement(methodLine.get(i));
            }
            methodGetSceneMapSpecBuild.addStatement("return sceneMap");
            javaClassBuilder.addMethod(methodGetSceneMapSpecBuild.build());
            TypeSpec javaClass = javaClassBuilder.build();
            JavaFile javaFile = JavaFile.builder(applicationId, javaClass).build();
    
            try {
                javaFile.writeTo(filer);
            } catch (IOException e) {
                messager.printMessage(Diagnostic.Kind.NOTE, e.getMessage());
            }
            return true;
        }
    
        @Override
        public SourceVersion getSupportedSourceVersion() {
            return SourceVersion.latestSupported();
        }
    
        @Override
        public Set<String> getSupportedAnnotationTypes() {
            Set<String> types = new HashSet<String>();
            types.add(Scene.class.getCanonicalName());
            return types;
        }
    
        @Override
        public Set<String> getSupportedOptions() {
            return Collections.singleton(APPLICATION_ID);
        }
    
        private boolean isIgnore(RoundEnvironment roundEnv) {
            Set<? extends Element> rootElements = roundEnv.getRootElements();
            if (rootElements.isEmpty())
                return true;
            for (Element element: rootElements) {
                String name = element.getSimpleName().toString();
                if ("SceneIds".equals(name))
                    return true;
            }
            return false;
        }
    }
    
    Scene.java
    package com.hyena.framework.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * Created by yangzc on 17/11/23.
     */
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    public @interface Scene {
    
        /**
         * 场景ID
         * @return 场景ID
         */
        String value();
    }
    
    
    build.gradle
    apply plugin: 'java'
    
    dependencies {
        compile fileTree(include: ['*.jar'], dir: 'libs')
        compile 'com.google.auto.service:auto-service:1.0-rc2'
        //谷歌的帮助我们快速实现注解处理器
        compile 'com.squareup:javapoet:1.7.0'
        //用来生成java文件的,避免字符串拼接
    }
    sourceCompatibility = "1.7"
    targetCompatibility = "1.7"
    
    dependencies中添加
    annotationProcessor project(":processor")
    
    defaultConfig中添加
    javaCompileOptions {
        //配置注解处理器参数
        annotationProcessorOptions {
            arguments = [applicationId: defaultConfig.applicationId]
        }
    }
    

    相关文章

      网友评论

          本文标题:Annotation Processor使用实例

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