资讯专栏INFORMATION COLUMN

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

andot / 2730人阅读

摘要:最后提供一段我用写的代码供参考行就能把任意代码结构转换成输出使用了库利用强大的属性描述符,写出通用的转换代码,避免了给每个结点类写对应的转换代码几十种结点类,要死啊。

另载于 http://www.qingjingjie.com/blogs/4

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

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

对任何AST结点都可调用方法structuralPropertiesForType(),你会得到List,其中每一项都代表这个结点所属的类的一个结构性字段(就是跟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,因此你将它强转为这个List类型,遍历它,对每个ImportDeclaration,调用getName().getFullyQualifiedName(),就得到了每个import的名称。(当然,对ImportDeclaration也可以假装不知道其类型,也用元数据来操控之)

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64243.html

相关文章

  • 前端进阶之路: 前端架构设计(1)-代码核心

    摘要:可能很多人和我一样首次听到前端架构这个词第一反应是前端还有架构这一说呢在后端开发领域系统规划和可扩展性非常关键因此架构师备受重视早在开发工作启动之前他们就被邀请加入到项目中而且他们会跟客户讨论即将建成的平台的架构要求使用还什么技术栈内容类型 可能很多人和我一样, 首次听到前端架构这个词, 第一反应是: 前端还有架构这一说呢? 在后端开发领域, 系统规划和可扩展性非常关键, 因此架构师备...

    DevYK 评论0 收藏0
  • 前端进阶之路: 前端架构设计(1)-代码核心

    摘要:可能很多人和我一样首次听到前端架构这个词第一反应是前端还有架构这一说呢在后端开发领域系统规划和可扩展性非常关键因此架构师备受重视早在开发工作启动之前他们就被邀请加入到项目中而且他们会跟客户讨论即将建成的平台的架构要求使用还什么技术栈内容类型 可能很多人和我一样, 首次听到前端架构这个词, 第一反应是: 前端还有架构这一说呢? 在后端开发领域, 系统规划和可扩展性非常关键, 因此架构师备...

    baishancloud 评论0 收藏0
  • 前端进阶之路: 前端架构设计(1)-代码核心

    摘要:可能很多人和我一样首次听到前端架构这个词第一反应是前端还有架构这一说呢在后端开发领域系统规划和可扩展性非常关键因此架构师备受重视早在开发工作启动之前他们就被邀请加入到项目中而且他们会跟客户讨论即将建成的平台的架构要求使用还什么技术栈内容类型 可能很多人和我一样, 首次听到前端架构这个词, 第一反应是: 前端还有架构这一说呢? 在后端开发领域, 系统规划和可扩展性非常关键, 因此架构师备...

    rockswang 评论0 收藏0
  • css选择器效率分析

    摘要:选择器的最后一部分,也就是选择器的最右边在这个例子中就是部分部分被称为关键选择器,它将决定你的选择器的效率如何是高还是低。因为最右边的关键选择器是最具体的,也符合上述的选择器优先级顺序。 赞助我以写出更好的文章 如果您觉得文章对您有帮助,可以逐个点击以下链接,类似于Google ads,不需要您付出任何费用,每天都可以来点一次噢,费用将由广告商承担,give me a cup of c...

    firim 评论0 收藏0

发表评论

0条评论

andot

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<