title: Annotation 使用备忘

date: 2018-01-02 20:48:43

tags: [Annotation]

categories: [Programming,Java]

概述

本文记录使用 javapoet 以及 auto-service 进行编译时注解的过程以及注意点.

最近又使用了一次编译时注解,期间产生了不少问题.

术语的解释

Element

这个代表被注解的元素.这个类有个很重要的方法,getEnclosingElement:这方法的含义是获取 包裹 element 最外围的元素.比如类的最外围的元素是 package.

    PackageElement pkgElement = (PackageElement) element.getEnclosingElement();

其他方法都很简单.

javapoet 库中一些重要的接口和方法

  1. TypeName: 对应了 java 代码中的一个类型元素,常用于声明一个方法参数,还有一些 collection 范型使用.
// 用来定一个 ComponentInfo 类的元素类型
TypeName mComponentInfoClassName = ClassName.get(ComponentInfo.class);
  1. ParameterizedTypeName 用来声明一个方法的参数.有个 get 方法,这个方法第一个参数是声明原生的类型,后面一个可变参数,声明第一个参数的参数.
// 声明一个参数的类型是 Map<String,List<ComponentInfo>>

ParameterizedTypeName paramListComponent = ParameterizedTypeName.get(ClassName.get(List.class), mComponentInfoClassName);
ParameterizedTypeName moduleLoaderParameter = ParameterizedTypeName.get(
ClassName.get(Map.class),
ClassName.get(String.class),
paramListComponent
);
  1. ParameterSpec

这个类代表方法的参数

// 声明一个方法的参数是:final Map<String,List<ComponentInfo>>  targetMap.
ParameterSpec injectParameterSpec = ParameterSpec.builder(moduleLoaderParameter, "targetMap", Modifier.FINAL).build();
  1. MethodSpec.Builder

    方法的构造器,用来构造一个方法.
// 用来构造一个私有方法,名字叫 inject ,参数是 Map<String,List<ComponentInfo>>  targetMap,String group,String pkg,String name,int type
MethodSpec.Builder injectElementBuilder = MethodSpec.methodBuilder("inject")
.addModifiers(Modifier.PRIVATE)
.addParameter(injectParameterSpec)
.addParameter(String.class, "group")
.addParameter(String.class, "pkg")
.addParameter(String.class, "name")
.addParameter(int.class, "type");

这个构造还可以继续添加语句

injectElementBuilder.addStatement("List<$T> list = targetMap.get(name)", ComponentInfo.class)
.beginControlFlow("if( list == null )")
.addStatement("list = new $T<>()", ArrayList.class)
.addStatement("targetMap.put(group, list)")
.endControlFlow()
.addStatement("ComponentInfo info = new ComponentInfo(type, group, pkg, name)")
.beginControlFlow("try")
.addStatement(" info.setClazz(Class.forName(pkg + name))")
.nextControlFlow("catch(Exception e)")
.addStatement("e.printStackTrace()")
.endControlFlow()
.addStatement("list.add(info)");

注意其中的两个 ControlFlow .

  1. TypeSpec

    用来声明一个类的描述
// 声明一个类,类名是 className,里面有两个方法
TypeSpec typeSpec = TypeSpec.classBuilder("className")
.addModifiers(Modifier.PUBLIC)
.addMethod(injectElementMethod)
.addMethod(injectMethodSpec)
.build();
  1. JavaFile

代表一个输出的 java 文件.

// 声明一个包名为 : com.steve.pkg 的java 文件.文件描述用的是一个 TypeSpec
JavaFile javaFile = JavaFile.builder("com.steve.pkg", typeSpec).build();

使用的注意事项

  1. 新版的 studio 以及不需要 android-apt
  2. 对于注解器的依赖可以通过 annotationProcessor project(':processor') 来对注解器工程进行依赖
  3. 对于注解配置选项可以在 gradle 中进行配置
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode rootProject.ext.android.versionCode
versionName rootProject.ext.android.versionName javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName()]
}
} }
  1. 对于注解器的注册,@AutoService(Processor.class),不要写错了,写成 process
  2. 注解器的配置项需要在注解器中声明 @SupportedOptions("moduleName")
  3. 注解器中的 log 不要随便打 error,不然就会停止解析,这点和 android 中的 log 有些差异.

Annotation 使用备忘2的更多相关文章

  1. Annotation 使用备忘

    title: Annotation 使用备忘 date: 2016-11-16 23:16:43 tags: [Annotation] categories: [Programming,Java] - ...

  2. Spring boot 注解简单备忘

    Spring boot 注解简单备忘 1.定义注解 package com.space.aspect.anno;import java.lang.annotation.*; /** * 定义系统日志注 ...

  3. GIS部分理论知识备忘随笔

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.高斯克吕格投影带换算 某坐标的经度为112度,其投影的6度带和3度带 ...

  4. python序列,字典备忘

    初识python备忘: 序列:列表,字符串,元组len(d),d[id],del d[id],data in d函数:cmp(x,y),len(seq),list(seq)根据字符串创建列表,max( ...

  5. Vi命令备忘

    备忘 Ctrl+u:向文件首翻半屏: Ctrl+d:向文件尾翻半屏: Ctrl+f:向文件尾翻一屏: Ctrl+b:向文件首翻一屏: Esc:从编辑模式切换到命令模式: ZZ:命令模式下保存当前文件所 ...

  6. ExtJs4常用配置方法备忘

    viewport布局常用属性 new Ext.Viewport({ layout: "border", renderTo: Ext.getBody(), defaults: { b ...

  7. [备忘] Automatically reset Windows Update components

    这两天遇到Windows 10的更新问题,官方有一个小工具,可以用来修复Windows Update的问题,备忘如下 https://support.microsoft.com/en-us/kb/97 ...

  8. ECMAScript 5(ES5)中bind方法简介备忘

    一直以来对和this有关的东西模糊不清,譬如call.apply等等.这次看到一个和bind有关的笔试题,故记此文以备忘. bind和call以及apply一样,都是可以改变上下文的this指向的.不 ...

  9. MFC通过txt查找文件并进行复制-备忘

    MFC基于对话框的Demo txt中每行一个23位的卡号. 文件夹中包含以卡号命名的图像文件.(fpt或者bmp文件) 要求遍历文件夹,找到txt中卡号所对应的图像文件,并复制出来. VC6.0写的. ...

随机推荐

  1. Java泛型学习一

    Java泛型 所谓泛型,就是变量类型的参数化.泛型是java1.5中引入的一个重要特征,通过引入泛型,可以使编译时类型安全,运行时更少抛出ClassCastException的可能.一提到参数化,最熟 ...

  2. TCL函数“参数自动补全” 与 “help 信息显示”

    tcl 函数参数自动补全和 help 信息显示 在EDA tool 中使用命令时,命令的参数可以通过 tab 键自动补全,而且可以使用 -help 显示帮助信息,使用起来很方便: 那么我们自己编写的 ...

  3. Oracle(二)SELECT语句执行顺序

    转载自:小强斋太-Study Notes,原文链接 从join on和where执行顺序认识T-SQL查询处理执行顺序 目录 一.样例 二.SELECT语句的处理过程 1. FROM阶段 2. WHE ...

  4. 算法练习——最长公共子序列的问题(LCS)

    问题描述: 对于两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列.X  Y   各自字符串有顺序,但是不一定需要相邻. 最长公共子串(Longest Common Subst ...

  5. C++ - 模板(template)中typename的使用方法

    声明template参数时, 前缀关键字class和typename可以互换; 使用关键字typename标识嵌套从属类型名称, 但不需在基类列表和成员初始化列表内使用. 从属名称(dependent ...

  6. Lambda 表达式的示例

    本文中的过程演示如何使用 lambda 表达式. 有关 lambda 表达式的概述,请参见 C++ 中的 Lambda 表达式. 有关 lambda 表达式结构的更多信息,请参见 Lambda 表达式 ...

  7. oracle 判断字段相等,但类型不同引起的性能问题

    最近做ogg数据同步,然后触发器加工数据放入另外一张表,由于数据量很大,一分钟几万条数据,由于一些条件字段类型不匹配,引起ogg阻塞,比较头大.最后分析发现性能问题.请看下图: phmxxh是varc ...

  8. oracle 事务 数据伪列

    在用户进行数据更新操作(DML)事务一定会起作用. 事务的出现会保证数据的完整性.一致性.在整个事务的处理过程之中主要使用两个操作命令: · 事务的提交(COMMIT):是真正的向数据库之中发出更新指 ...

  9. mysql/mariadb将选择查询的结果重新生成一张新表格

    比如想要生成类似如下的表格 mysql> select student.*,sc.cno,course.cname,sc.grade,course.cpno,course.ccredit fro ...

  10. 在CentOS7.6上安装自动化运维工具Ansible以及playbook案例实操

    前言 Ansible是一款优秀的自动化IT运维工具,具有远程安装.远程部署应用.远程管理能力,支持Windows.Linux.Unix.macOS和大型机等多种操作系统. 下面就以CentOS 7.6 ...