【中软国际】HarmonyOS 注解的使用 原创 精华

深开鸿开发板
发布于 2021-8-19 13:09
浏览
1收藏

概述

主要作用:简化代码,提高开发效率。

通过自定义的注解使我们能够在源码阶段、编译阶段、运行阶段对代码进行操控。减轻编写”样板”代码的负担,使代码干净易读。

元注解

在自定义注解的时候,需要使用到元注解来定义我们的注解

元注解 说明 值(枚举) 值说明
@Target 注解用在什么地方 1、ElementType.TYPE 1、接口、类、枚举
2、ElementType.FIELD 2、字段、枚举常量
3、ElementType.METHOD 3、方法
4、ElementType.PARAMETER 4、方法参数
5、ElementType.CONSTRUCTOR 5、构造函数
6、ElementType.LOCAL_VARIABLE 6、局部变量
7、ElementType.ANNOTATION_TYPE 7、注解
8、ElementType.PACKAGE 8、包
@Retention 注解在哪个阶段有效 1、RetentionPolicy.SOURCE 1、源码阶段
2、RetentionPolicy.CLASS 2、编译阶段
3、RetentionPolicy.RUNTIME 3、运行阶段

自定义注解

1、声明注解

功能:检测类中是否有规范的get方法

新建java libray的module,命名为annotation,创建注解类。

@Target({ElementType.TYPE})//用于 接口、类、枚举
@Retention(RetentionPolicy.CLASS)//编译阶段
public @interface CheckGetter {
}

2、编写注解处理器

新建java libray的module,命名为annotation_processor

在build.gradle中添加依赖

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    //添加本地依赖
    implementation project(':annotation')
}

注解处理器所做的工作,就是在代码编译的过程中,找到我们指定的注解,加上功能逻辑做出相应的处理,或者生成java文件

继承AbstractProcessor,重写对应的方法

package com.example.processor;

import com.example.annotation.CheckGetter;

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.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementFilter;
import javax.tools.Diagnostic;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 注解处理器
 * 检查是否有get方法
 */
public class CheckGetterProcessor extends AbstractProcessor {
    /**
     * 初始化
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }

    /**
     * 返回支持的源码版本
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    /**
     * 支持的注解类型
     * 如果集合为空,不执行process方法
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> annotationTypes = new HashSet<>();
        annotationTypes.add(CheckGetter.class.getCanonicalName());
        return annotationTypes;
    }

    /**
     * 解析方法
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //获取自定义注解使用到的类集合
        Set<TypeElement> typeElementSet = ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(CheckGetter.class));

        //遍历类
        for (TypeElement annotatedClass : typeElementSet) {
            //获取类中的属性集合
            List<VariableElement> variableElementList = ElementFilter.fieldsIn(annotatedClass.getEnclosedElements());
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "属性列表:" + variableElementList);
            //遍历属性
            for (VariableElement field : variableElementList) {
                //根据get方法规则,判断是否包含get方法
                if (!containsGetter(annotatedClass, field.getSimpleName().toString())) {
                    processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
                            String.format("缺少get方法! 类名:%s \t参数名:%s", annotatedClass.getQualifiedName(), field.getSimpleName()));
                }
            }
        }
        return false;
    }

    /**
     * 根据get方法规则,判断是否包含get方法
     *
     * @param typeElement  类
     * @param variableName 属性名
     * @return 是否包含get方法
     */
    private boolean containsGetter(TypeElement typeElement, String variableName) {
        // get方法命名规则:getName
        String getter = "get" + variableName.substring(0, 1).toUpperCase() + variableName.substring(1).toLowerCase();

        //获取类中的所有方法
        List<ExecutableElement> methodElementList = ElementFilter.methodsIn(typeElement.getEnclosedElements());
        processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "方法列表:" + methodElementList);

        //遍历方法
        for (ExecutableElement methodElement : methodElementList) {
            //方法规则:非静态、命名规则、无参数
            if (!methodElement.getModifiers().contains(Modifier.STATIC) &&
                    methodElement.getSimpleName().toString().equals(getter) &&
                    methodElement.getParameters().isEmpty()) {
                return true;
            }
        }
        return false;
    }
}

3、注册注解处理器

1、需要在 annotation_processor模块的 main 目录下新建 resources 资源文件夹;

2、在 resources文件夹下建立 META-INF/services 目录文件夹;

3、在 META-INF/services 目录文件夹下创建 javax.annotation.processing.Processor 文件;

4、在 javax.annotation.processing.Processor 文件写入注解处理器的全称,包括包路径

4、使用注解

在entry模块的build.gradle文件中添加依赖

dependencies {
    ......
    
    implementation project(':annotation')
    annotationProcessor project(':annotation_processor')
}

新建Person类,使用注解,属性age不生成get方法

import com.example.annotation.CheckGetter;

@CheckGetter
public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

运行项目报错:

缺少get方法! 类名:com.example.annotation.demo.Person 参数名:age

作者:梁青松

更多原创内容请关注:中软国际 HarmonyOS 技术学院

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2021-8-19 15:16:55修改
3
收藏 1
回复
举报
1条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

好的注解是优秀代码必不可少的部分!

回复
2021-8-19 13:43:43
回复
    相关推荐