博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
又一 Java 注解(annotation)用例
阅读量:4091 次
发布时间:2019-05-25

本文共 4610 字,大约阅读时间需要 15 分钟。

之前提过Multiline注解,可以在低版本的Java语言中通过注释与注解优雅地实现多行文本的定义。将Multiline-String拓展为Multiline-Byte Array后,意犹未尽,于是开了个空工程(纯Java无groovy、maven管理)测试annotation。但是……怎么都不对,注解不生效,都没调用!明明,资源文件中meta-inf信息填好,处理器挂钩,但是写好的注解毛都没处理。一开始以为是idea的问题,换了Eclipse,也还是不行……

索性放弃另起炉灶的想法。干脆再次拓展Multiline模块。这回的需求是,简化程序的标志位操作。我一个项目中差不多用光了4个长整型标志位容器,这之中不单单是一些布尔值,好包括两位到三位的短整数。结果,

管理设置的那个文件变成了这样……

在这里插入图片描述

两千多行了……

我要让一个设置就占一两行!

鼓捣一番后后,终于成功:

在这里插入图片描述

原先,直接把标志位mask写了出来,现在,我只需配置好方法名称、标志位容器,然后再注解的变量中配置标志位位置、默认值偏移、debug数值等等即可!

以get方法为例,标志位操作的完整的“公式”如下:

  • 短整数
    (((FirstFlag>>flagPos) & mask)[+shift])[%max][+elevation];
public int eval(int flagPos, int flagSize, int shift, int elevation, int max) {		int mask = (1<
>flagPos) & mask)+shift)%max+elevation); }

shift用于偏移默认值。shift之后的变量皆为可选,所以注解处理器根据变量不同处理生成不同的方法实体。最简短的核心是: (FirstFlag>>flagPos) & mask。max代表最大使用数值,比如一个111b三位短整数标志,容纳的最大数是7,但是有可能只用到了100b,也就是0、1、2、3、4五个数值。

  • 布尔标志
public boolean getInPageSearchVisible() {		return (FirstFlag & 0x100000000000l) == 0x100000000000l;	}

注解处理(修改方法体的实现):

JCTree.JCMethodDecl metDcl = (JCTree.JCMethodDecl) elementUtils.getTree(field);Multiline annotation = field.getAnnotation(Multiline.class);List
statements = metDcl.body.stats;JCTree.JCPrimitiveTypeTree RETType = (JCTree.JCPrimitiveTypeTree) retType;
  • 短整数
JCTree.JCExpressionStatement stat = (JCTree.JCExpressionStatement) _1st;JCTree.JCAssign assgn = (JCTree.JCAssign) stat.expr;JCTree.JCExpression flag = (JCTree.JCIdent) assgn.getVariable(); //JCTree.JCIdentint flagPos = annotation.flagPos();int mask = (1<
parms = metDcl.getParameters();if(RETType.typetag==TypeTag.INT) { //CMN.Log("mask", mask); JCTree.JCBinary core = maker.Binary(JCTree.Tag.SR, flag, maker.Literal(flagPos)); JCTree.JCBinary basic = maker.Binary(JCTree.Tag.BITAND, maker.Parens(core), maker.Literal(mask)); JCTree.JCExpression finalExpr = basic; if(shift!=0||max
0) { finalExpr = maker.Binary(JCTree.Tag.PLUS, finalExpr, maker.Literal(annotation.elevation())); } finalExpr = maker.TypeCast(maker.TypeIdent(TypeTag.INT), finalExpr); CMN.Log(121,finalExpr); metDcl.body = maker.Block(0, List.from(new JCTree.JCStatement[]{maker.Return(finalExpr)}));}
  • 布尔变量
else if(RETType.typetag==TypeTag.BOOLEAN) {    int debugVal = annotation.debug();    int size = parms.size();    if(size==1) {        JCVariableDecl val=parms.get(0);        JCTree.JCPrimitiveTypeTree type = (JCTree.JCPrimitiveTypeTree) val.getType();        if(type.typetag==TypeTag.LONG||type.typetag==TypeTag.INT) {            flag = maker.Ident(val);        }    }    JCTree.JCBinary core = maker.Binary(JCTree.Tag.BITAND, flag, maker.Literal(maskVal));    JCTree.JCExpression finalExpr = maker.Binary(shift==0?JCTree.Tag.NE:JCTree.Tag.EQ, maker.Parens(core), maker.Literal(0));    if(debugVal>=0) {        finalExpr = maker.Literal(debugVal==1);    }    metDcl.body = maker.Block(0, List.from(new JCTree.JCStatement[]{maker.Return(finalExpr)}));}

get的注解实现便如此……

本想试试生成set方法的,但还是一样地弄一遍比较简单。

其中,改变方法体通过 metDcl.body = …… 赋值实现。所有语句均通过 TreeMaker 组装,列表如下:

maker.Literal(val) :“字面义”,用原生数据创建JcExpressionmaker.Ident(dcl) :意义不明,Identity吗?用变量声明创建JcExpressionmaker.Parens(exp) :套括号maker.Binary(运算符符Tag,左运算数JcExpression,右运算数JcExpression) :二元操作maker.Unary(运算符符Tag,运算数JcExpression) : 一元操作maker.Assign(变量JcExpression,数值JcExpression) :创建赋值表达(JcExpression)maker.Exec(maker.Assign()) 创建赋值语句 :(JCTree.JCExpressionStatement)maker.If(条件JcExpression, 真分支JCStatement, 假分支JCStatement) :创建If语句(JCStatement)……

然后,修改方法体是这样的:

JCTree.JCStatement[] stats = new JCTree.JCStatement[2];stats[0]=语句……metDcl.body = maker.Block(0, List.from(stats));

maker.Binary是二元操作,本来还以这是二进制的意思呢,直到看到 maker.Unary ……

一元、二元运算符均通过 JCTree.Tag 标明,列表如下:

JCTree.Tag.BITOR 按位或JCTree.Tag.BITAND 按位与JCTree.Tag.SL shift left 左移JCTree.Tag.SR shift left 右移JCTree.Tag.EQ 相等JCTree.Tag.NE 不等JCTree.Tag.LT 小于JCTree.Tag.GT 大于JCTree.Tag.PLUS 加JCTree.Tag.MOD 取模JCTree.Tag.NOT 非……

注解的设计:

@Multiline(flagPos=9, flagSize=2, shift=1, elevation=2, max=0) public int getCycleTyleViaAnnot(){ FirstFlag=FirstFlag; throw new RuntimeException(); }

展开看

@Multiline(flagPos=9, flagSize=2, shift=1, elevation=2, max=0)

public int getCycleTyleViaAnnot()

{

  • FirstFlag=FirstFlag; 自赋值,用于注解处理中获取标志位容器的JcExpression。
  • throw new RuntimeException(); 直接抛出

}

注解本身的定义:

@Target({ElementType.FIELD, ElementType.METHOD})@Retention(RetentionPolicy.SOURCE)public @interface Multiline {	boolean trim() default true;		int flagPos() default 0;	int flagSize() default 1;	int shift() default 0;	int elevation() default 0;	int max() default 0;	int debug() default -1;}

此时Multiline已经不能称作Multiline了,当改名为:

MetaLine · 元线

另外,这是什么意思,idea欺负我不懂英文么?

在这里插入图片描述

转载地址:http://fmbii.baihongyu.com/

你可能感兴趣的文章
React + TypeScript 实现泛型组件
查看>>
TypeScript 完全手册
查看>>
React Native之原理浅析
查看>>
Git操作清单
查看>>
基础算法
查看>>
前端面试
查看>>
React Hooks 异步操作踩坑记
查看>>
聊聊编码那些事,顺带实现base64
查看>>
TypeScript for React (Native) 进阶
查看>>
React 和 ReactNative 的渲染机制/ ReactNative 与原生之间的通信 / 如何自定义封装原生组件/RN中的多线程
查看>>
JavaScript实现DOM树的深度优先遍历和广度优先遍历
查看>>
webpack4 中的 React 全家桶配置指南,实战!
查看>>
react 设置代理(proxy) 实现跨域请求
查看>>
通过试题理解JavaScript
查看>>
webpack的面试题总结
查看>>
实践这一次,彻底搞懂浏览器缓存机制
查看>>
Koa2教程(常用中间件篇)
查看>>
React Hooks 完全指南
查看>>
React16常用api解析以及原理剖析
查看>>
教你发布你npm包
查看>>