Java代码分析器(三): 以强大的属性描述符写出通用代码

砾歌枚举
• 阅读 5665

上篇介绍的形形色色的语法元素大概让人眼花缭乱了,而且每种元素都对应一个Java类。知道是一回事,使用就是另一回事了,这么多个类,要给每个类写对应的处理代码,不胜其烦。ASTVisitor虽然能自动遍历语法树,但是并不能帮你处理每一种结点。

好在JDT提供了更加抽象的属性描述符(property descriptor),寥寥几个类就能掌控所有Java语法。用术语来说,上篇的那些类属于异构AST,本篇讲的是同构AST。

对任何AST结点都可调用方法structuralPropertiesForType(),你会得到List<StructuralPropertyDescriptor>,其中每一项都代表这个结点所属的类的一个结构性字段(就是跟AST有关的字段)。

StructuralPropertyDescriptor 是一个抽象类,有三个子类:SimplePropertyDescriptor, ChildPropertyDescriptor, ChildListPropertyDescriptor。这些东西是元数据,用来描述各种语法元素的固有结构,使用它们有种在用Java反射的感觉。

SimplePropertyDescriptor 表示这个字段存放的不是AST结点,而是个值,可能是int, String,Operator之类的,SimplePropertyDescriptor.valueType 能告诉我们这个值是什么类型。

ChildPropertyDescriptor 表示这个字段存放的是一个AST结点,比如我们解析了一个class,得到typeDeclaration结点,然后调用typeDeclaration.structuralPropertiesForType(),得到的list中有一项就是typeName的描述符,嗯,就是AbstractTypeDeclaration类的typeName字段,字段类型为SimpleName。

ChildListPropertyDescriptor 表示这个字段存放的是一组AST结点! 比如AbstractTypeDeclaration拥有一组bodyDeclarations,而CompilationUnit则拥有一组imports。bodyDeclarations和imports都是List!

有了描述符能做什么呢? 可以自由访问一棵语法树了。

我们来想象一个流程:你有一个java文件,你把它交给JDT的parser,解析出一个CompilationUnit cu,也就是一棵语法树的根结点。调用cu.structuralPropertiesForType(),得到描述符的list,循环遍历list,对每个描述符prop,用instanceof判断具体类型(总共就3个类型),分别做"不同处理"。

不同处理:instanceof操作发现某个描述符是ChildListPropertyDescriptor, 于是你把描述符强转(cast)成该类型,调用prop.getId()得到"imports",哦,是imports字段啊,调用prop.getElementType()得到ImportDeclaration.class,确认了这一发现。然后你调用cu.getStructuralProperty(prop)得到一个object,你知道它实际是List<ImportDeclaration>,因此你将它强转为这个List类型,遍历它,对每个ImportDeclaration,调用getName().getFullyQualifiedName(),就得到了每个import的名称。(当然,对ImportDeclaration也可以假装不知道其类型,也用元数据来操控之)

由此你就完成了一个分析流程。因为不用关心具体的结点类型,所以你可以方便地进行一些宏观、抽象的分析。

最后提供一段我用Scala写的代码供参考(50行就能把任意Java代码结构转换成JSON输出, 使用了lift json库):
https://github.com/sorra/Lank...
利用强大的属性描述符,写出通用的JSON转换代码,避免了给每个结点类写对应的JSON转换代码(几十种结点类,要死啊)。

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Stella981 Stella981
4年前
Python+Selenium自动化篇
本篇文字主要学习selenium定位页面元素的集中方法,以百度首页为例子。0.元素定位方法主要有:id定位:find\_element\_by\_id('')name定位:find\_element\_by\_name('')class定位:find\_element\_by\_class\_name(''
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Stella981 Stella981
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
4年前
CSS基本语法及页面引用
css基本语法及页面引用(1)css基本语法css的定义方法是:选择器{属性:值;属性:值;属性:值;}选择器是将样式和页面元素关联起来的名称,属性是希望设置的样式属性每个属性有一个或多个值。代码示例:/css注释ctrlshift"/"/d
Stella981 Stella981
4年前
Python+Selenium练习篇之5
前面介绍了,XPath,id,class,linktext,partiallinktext,tagname,name七大元素定位方法,本文介绍webdriver支持的最后一个方法:by\_css。css和XPath类似,也需要掌握一些语法,才能写出正确的,完整的css选择表达式。相关脚本代码如下:codingu
Wesley13 Wesley13
4年前
Java的类继承
知识点1、继承作用:提高代码的重用性,继承之后子类可以继承父类中的属性和方法减少重复代码条件:子类和父类要满足isa的逻辑关系,才能使用继承。如:苹果isa水果语法:使用extends连接子类和父类。子类extends父类Java是单继承,一个类只能继承一个父类。子类不能继承父类私有的属性,但是可以
Easter79 Easter79
4年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Easter79 Easter79
4年前
SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)
首先在shiro配置类中注入rememberMe管理器!复制代码(https://oscimg.oschina.net/oscnet/675f5689159acfa2c39c91f4df40a00ce0f.gif)/cookie对象;rememberMeCookie()方法是设置Cookie的生成模
Wesley13 Wesley13
4年前
Java工程中各种带有O的对象分类笔记
在Java工程里面,我们总会碰到各种不同的带有O的对象,对于一个小白来说,经常会混淆这些对象的使用场景,所以在这里mark一下,让自己的代码更加规范,但这个也是Java被诟病的地方,不同的业务需要给它写各种各样的映射类。PO:persistentobject,持久对象。与数据库里表中的字段对应。PO是一些属性,以及s
砾歌枚举
砾歌枚举
Lv1
明眸皓齿谁复见,只有丹青余泪痕。
文章
1
粉丝
0
获赞
0
热门文章

暂无数据