【中软国际】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 {
}
  • 1.
  • 2.
  • 3.
  • 4.

2、编写注解处理器

新建java libray的module,命名为annotation_processor

在build.gradle中添加依赖

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

注解处理器所做的工作,就是在代码编译的过程中,找到我们指定的注解,加上功能逻辑做出相应的处理,或者生成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;
    }
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.

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')
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

新建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;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

运行项目报错:

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

作者:梁青松

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

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

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

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

回复
2021-8-19 13:43:43


回复
    相关推荐
    HarmonyOS官方合作伙伴、生态全场景解决方案商、致力于生态建设
    觉得TA不错?点个关注精彩不错过
    32
    帖子
    0
    视频
    1035
    声望
    435
    粉丝
    社区精华内容