栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android 自定义注解处理器

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android 自定义注解处理器

        之前我们可能用过dagger、hilt之类的注解,使用这些注解可以方便我们的工作,减少我们的代码编写量。因此,本文主要是介绍如何自定义一个注解处理器。可以分为2个部分,一、定义注解和注解处理器;二、注解使用演示。

        本文的目标:定义一个类构造方法上的注解DemoAnnotation,并使用此注解生成一个工厂类。注解的执行结果如下图所示

一、注解和注解处理器

        首先我们要新建一个”Java or Kotlin Library“组件项目 ,然后 对此子项目的build.gradle文件进行配置,如下:

plugins {
    id 'java-library'
    id 'kotlin'
    id 'kotlin-kapt'
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.5.31"
    kapt 'com.google.auto.service:auto-service:1.0-rc6'
    compileonly 'com.google.auto.service:auto-service:1.0-rc6'
}

        1、定义注解

        我们定义一个在类构造方法上的注解,如下所示:

package com.example.demoprocessor

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CONSTRUCTOR)
annotation class DemoAnnotation

        2、定义注解处理器

@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({DemoProcessor.DEMO_ANNOTATION})
public class DemoProcessor extends AbstractProcessor {
    static final String DEMO_ANNOTATION = "com.example.demoprocessor.DemoAnnotation";
    @Override
    public boolean process(Set annotations, RoundEnvironment roundEnv) {
        return new DemoAnnotationProcessor().process(annotations, roundEnv, processingEnv);
    }
}

        我们需要使用@SupportedAnnotationTypes指明注解的名称(包名+注解名),然后使用@AutoService注解,作用是可以帮我们在注解路径里自动添加当前的注解类。

        本文注解处理器的实现放在DemoAnnotationProcessor类中,如下所示:

package com.example.demoprocessor

import java.io.IOException
import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.Modifier
import javax.lang.model.element.PackageElement
import javax.lang.model.element.TypeElement
import javax.tools.JavaFileObject

class DemoAnnotationProcessor {

    fun process(
        annotations: Set,
        roundEnv: RoundEnvironment,
        processingEnv: ProcessingEnvironment
    ): Boolean {
        println("start process")
        if (roundEnv.rootElements.size == 0) {
            return false
        }
        for (annotation in annotations) {
            // 留下需要的注解
            if (!annotation.qualifiedName.toString().contains(DEMO_ANNOTATION)) {
                continue
            }
            val elements = roundEnv.getElementsAnnotatedWith(annotation)
            for (element in elements) {
                // 去掉非方法的注解
                if (element !is ExecutableElement) {
                    continue
                }
                // 检查被注解的方法是否符合要求
                if (!checkHasNoErrors(element)) {
                    continue
                }
                // 获取类
                val classElement = element.enclosingElement as TypeElement
                // 获取包
                val packageElement = getPackageElement(classElement)
                createServiceClass(
                    packageElement!!.qualifiedName.toString(),
                    classElement.simpleName.toString(),
                    classElement.simpleName.toString(),
                    processingEnv
                )
            }
        }
        return true
    }

    private fun createServiceClass(
        pkName: String,
        simpleClazzName: String,
        serviceName: String,
        processingEnv: ProcessingEnvironment
    ) {
        println("createServiceClass")
        val className = "$pkName.$simpleClazzName"
        val builder = StringBuilder()
            .append("package com.example.annotationprocessor.generated;nn")
            .append("import $className;nn")
            .append("public class GeneratedClass$serviceName {nn") // open class
            .append("tpublic $simpleClazzName getInstance() {n") // open method
            .append("ttreturn ")
        builder.append("new $simpleClazzName()")
        builder.append(";n") // end return
            .append("t}n") // close method
            .append("}n") // close class
        try { // write the file
            val source: JavaFileObject = processingEnv.filer
                .createSourceFile(
                    "com.example.annotationprocessor.generated.GeneratedClass"
                            + serviceName
                )
            val writer = source.openWriter()
            writer.write(builder.toString())
            writer.flush()
            writer.close()
        } catch (e: IOException) {
            // Note: calling e.printStackTrace() will print IO errors
            // that occur from the file already existing after its first run, this is normal
        }
    }

    private fun getPackageElement(subscriberClass: TypeElement): PackageElement? {
        var candidate = subscriberClass.enclosingElement
        while (candidate !is PackageElement) {
            candidate = candidate.enclosingElement
        }
        return candidate
    }

    private fun checkHasNoErrors(initMethod: ExecutableElement): Boolean {
        if (!initMethod.modifiers.contains(Modifier.PUBLIC)) {
            return false
        }
        return initMethod.parameters.size <= 0
    }

    private final val DEMO_ANNOTATION = "com.example.demoprocessor.DemoAnnotation"
}

        注意在此过程中,只能创建文件,而不能修改已经存在的文件。

二、注解的使用

        首先,我们需要在app项目的build.gradle里添加对注解处理的依赖。注意,要使用kapt或annotationProcessor添加对注解处理器的依赖,然后使用implement 添加对注解的依赖。因为本文将注解和注解处理器都放在了一个组件里,所以会用kapt和implement对同一组件添加依赖,如下所示:

    implementation project(':demoprocessor')
    kapt project(":demoprocessor")

        在添加完成之后,就可以使用注解了,如下:

class TestAnnotation @DemoAnnotation constructor(){

    init {
        // 模拟初始化操作
        var i = 0
        i++
    }
}

        最后,在build之后,生成的注解文件如开篇的第一张图所示。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/726739.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号