本文共 4610 字,大约阅读时间需要 15 分钟。
之前提过Multiline注解,可以在低版本的Java语言中通过注释与注解优雅地实现多行文本的定义。将Multiline-String拓展为Multiline-Byte Array后,意犹未尽,于是开了个空工程(纯Java无groovy、maven管理)测试annotation。但是……怎么都不对,注解不生效,都没调用!明明,资源文件中meta-inf信息填好,处理器挂钩,但是写好的注解毛都没处理。一开始以为是idea的问题,换了Eclipse,也还是不行……
索性放弃另起炉灶的想法。干脆再次拓展Multiline模块。这回的需求是,简化程序的标志位操作。我一个项目中差不多用光了4个长整型标志位容器,这之中不单单是一些布尔值,好包括两位到三位的短整数。结果,
管理设置的那个文件变成了这样……
两千多行了……
我要让一个设置就占一两行!
鼓捣一番后后,终于成功:
原先,直接把标志位mask写了出来,现在,我只需配置好方法名称、标志位容器,然后再注解的变量中配置标志位位置、默认值偏移、debug数值等等即可!以get方法为例,标志位操作的完整的“公式”如下:
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);Liststatements = 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)}));}
本想试试生成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()
{}
注解本身的定义:
@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了,当改名为:
另外,这是什么意思,idea欺负我不懂英文么?
转载地址:http://fmbii.baihongyu.com/