eclipse中ast_JavaParser中AST节点的观察者

eclipse中ast

我们离JavaParser 3.0的第一个候选发布版本越来越近。 我们添加的最后一项功能是支持观察抽象语法树的所有节点的更改。 当我为此功能编写代码时,我收到了Danny van Bruggen(又名Matozoid)和Cruz Maximilien的宝贵反馈。 因此,我使用“我们”来指代JavaParser团队。

AST节点上的哪些观察者可以用于?

我认为这对于JavaParser的生态系统来说是非常重要的功能,因为它通过对AST所做的更改做出React,使与JavaParser的集成变得更加容易。 可以观察到的可能更改是为类设置新名称或添加新字段。 不同的工具可以以不同的方式对这些变化做出React。 例如:

  • 编辑者可以更新其符号列表,该列表可用于自动完成等操作
  • 一些框架可以重新生成源代码以反映更改
  • 可以执行验证以验证新更改是否导致无效的AST
  • JavaSymbolSolver之类的库可以重新计算表达式的类型

这些只是我想到的一些想法,但我认为使用JavaParser的大多数方案都可以从对更改做出React的可能性中受益。

AstObserver

JavaParser 3.0 AST基于Nodes和NodeLists。 一个节点,例如一个TypeDeclaration ,可以具有不同的子组。 当这些组可以包含多个节点时,我们使用NodeLists。 例如,一个TypeDeclarations可以具有多个成员(字段,方法,内部类)。 因此,每个TypeDeclaration都有一个NodeList来包含字段,一个NodeList来包含方法,等等。其他子项(如TypeDeclaration的名称)则直接包含在一个节点中。

我们引入了一个名为AstObserver的新接口 AstObserver接收节点和NodeList上的更改。

/*** An Observer for an AST element (either a Node or a NodeList).*/
public interface AstObserver {/*** Type of change occurring on a List*/public enum ListChangeType {ADDITION,REMOVAL}/*** The value of a property is changed** @param observedNode owner of the property* @param property property changed* @param oldValue value of the property before the change* @param newValue value of the property after the change*/void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue);/*** The parent of a node is changed** @param observedNode node of which the parent is changed* @param previousParent previous parent* @param newParent new parent*/void parentChange(Node observedNode, Node previousParent, Node newParent);/*** A list is changed** @param observedNode list changed* @param type type of change* @param index position at which the changed occurred* @param nodeAddedOrRemoved element added or removed*/void listChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved);
}

观察什么

现在我们有了一个AstObserver ,我们需要确定它应该接收哪些更改。 我们考虑了三种可能的情况:

  1. 仅观察一个节点,例如ClassDeclaration。 观察者将收到有关该节点上的更改的通知(例如,如果类更改名称),而不是其任何后代的通知。 例如,如果类更改名称的字段不会通知观察者
  2. 对于观察者注册时的节点及其所有后代。 在这种情况下,如果我注册了ClassDeclaration的观察者,则将通知我有关类及其所有字段和方法的更改。 如果添加了新字段并在以后进行了修改,那么我将不会收到有关这些更改的通知
  3. 对于一个节点及其所有后代,在观察者注册时存在的节点和以后添加的节点。

因此,Node现在具有此方法:

/*** Register a new observer for the given node. Depending on the mode specified also descendants, existing* and new, could be observed. For more details seeObserverRegistrationMode .*/public void register(AstObserver observer, ObserverRegistrationMode mode) {if (mode == null) {throw new IllegalArgumentException("Mode should be not null");}switch (mode) {case JUST_THIS_NODE:register(observer);break;case THIS_NODE_AND_EXISTING_DESCENDANTS:registerForSubtree(observer);break;case SELF_PROPAGATING:registerForSubtree(PropagatingAstObserver.transformInPropagatingObserver(observer));break;default:throw new UnsupportedOperationException("This mode is not supported: " + mode);}}

为了区分这三种情况,我们仅使用一个枚举( ObserverRegistrationMode )。 稍后,您将看到我们如何实现PropagatingAstObserver

实施对观察员的支持

如果JavaParser基于诸如EMF之类的元建模框架,则这将非常简单。 鉴于情况并非如此,我需要在AST类的所有设置器中添加一个通知调用(其中有90个左右)。

因此,当在特定节点上调用setter时,它将通知所有观察者。 简单。 以TypeDeclaration <T>中的 setName 为例

@Override
public T setName(SimpleName name) {notifyPropertyChange(ObservableProperty.NAME, this.name, name);this.name = assertNotNull(name);setAsParentNodeOf(name);return (T) this;
}

鉴于我们没有适当的元模型,因此没有属性的定义。 因此,我们在枚举中添加了一个名为ObservableProperty的属性列表。 通过这种方式,观察者可以检查更改了哪个属性并决定如何做出React。

观察者的内部等级

出于性能原因,每个节点都有自己的观察者列表。 当我们要观察节点的所有后代时,我们只需向该子树中的所有节点和节点列表添加相同的观察者即可。

但是,这还不够,因为在某些情况下,您可能还需要观察放置观察者后添加到子树中的所有节点。 我们通过使用PropagatingAstObserver做到这一点。 这是一个AstObserver,当看到一个新节点已附加到该节点时,它也开始观察该新节点。 简单吧?

/*** This AstObserver attach itself to all new nodes added to the nodes already observed.*/
public abstract class PropagatingAstObserver implements AstObserver {/*** Wrap a given observer to make it self-propagating. If the given observer is an instance of PropagatingAstObserver* the observer is returned without changes.*/public static PropagatingAstObserver transformInPropagatingObserver(final AstObserver observer) {if (observer instanceof PropagatingAstObserver) {return (PropagatingAstObserver)observer;}return new PropagatingAstObserver() {@Overridepublic void concretePropertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {observer.propertyChange(observedNode, property, oldValue, newValue);}@Overridepublic void concreteListChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved) {observer.listChange(observedNode, type, index, nodeAddedOrRemoved);}@Overridepublic void parentChange(Node observedNode, Node previousParent, Node newParent) {observer.parentChange(observedNode, previousParent, newParent);}};}@Overridepublic final void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {considerRemoving(oldValue);considerAdding(newValue);concretePropertyChange(observedNode, property, oldValue, newValue);}@Overridepublic final void listChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved) {if (type == ListChangeType.REMOVAL) {considerRemoving(nodeAddedOrRemoved);} else if (type == ListChangeType.ADDITION) {considerAdding(nodeAddedOrRemoved);}concreteListChange(observedNode, type, index, nodeAddedOrRemoved);}public void concretePropertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {// do nothing}public void concreteListChange(NodeList observedNode, ListChangeType type, int index, Node nodeAddedOrRemoved) {// do nothing}@Overridepublic void parentChange(Node observedNode, Node previousParent, Node newParent) {// do nothing}private void considerRemoving(Object element) {if (element instanceof Observable) {if (((Observable) element).isRegistered(this)) {((Observable) element).unregister(this);}}}private void considerAdding(Object element) {if (element instanceof Node) {((Node) element).registerForSubtree(this);} else if (element instanceof Observable) {((Observable) element).register(this);}}}

观察员在行动

让我们看看这在实践中如何工作:

// write some code and parse it
String code = "class A { int f; void foo(int p) { return 'z'; }}";
CompilationUnit cu = JavaParser.parse(code);// set up our observer
List changes = new ArrayList<>();
AstObserver observer = new AstObserverAdapter() {@Overridepublic void propertyChange(Node observedNode, ObservableProperty property, Object oldValue, Object newValue) {changes.add(String.format("%s.%s changed from %s to %s", observedNode.getClass().getSimpleName(), property.name().toLowerCase(), oldValue, newValue));}
};
cu.getClassByName("A").register(observer, /* Here we could use different modes */);// Doing some changes
cu.getClassByName("A").setName("MyCoolClass");
cu.getClassByName("MyCoolClass").getFieldByName("f").setElementType(new PrimitiveType(PrimitiveType.Primitive.Boolean));
cu.getClassByName("MyCoolClass").getMethodsByName("foo").get(0).getParamByName("p").setName("myParam");
// Here we are adding a new field and immediately changing it
cu.getClassByName("MyCoolClass").addField("int", "bar").getVariables().get(0).setInit("0");// If we registered our observer with mode JUST_THIS_NODE
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass"), changes);// If we registered our observer with mode THIS_NODE_AND_EXISTING_DESCENDANTS
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass","FieldDeclaration.element_type changed from int to boolean","VariableDeclaratorId.name changed from p to myParam"), changes);// If we registered our observer with mode SELF_PROPAGATING
assertEquals(Arrays.asList("ClassOrInterfaceDeclaration.name changed from A to MyCoolClass","FieldDeclaration.element_type changed from int to boolean","VariableDeclaratorId.name changed from p to myParam","FieldDeclaration.modifiers changed from [] to []","FieldDeclaration.element_type changed from empty to int","VariableDeclaratorId.array_bracket_pairs_after_id changed from com.github.javaparser.ast.NodeList@1 to com.github.javaparser.ast.NodeList@1","VariableDeclarator.init changed from null to 0"), changes);

结论

我对此新功能感到非常兴奋,因为我认为它使JavaParser可以完成更多很酷的事情。 我认为我们作为提交者的工作是使其他人能够做我们目前未预见的事情。 我们应该只是充当推动者,然后躲开。

我真的很好奇,看看人们会如何发展。 顺便说一句,您知道您想让我们知道的任何使用JavaParser的项目吗? 在GitHub上发表评论或打开问题,我们期待您的来信!

翻译自: https://www.javacodegeeks.com/2016/11/observers-ast-nodes-javaparser.html

eclipse中ast

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/335567.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java模拟登陆_java-模拟登陆练习(示例代码)

package com.day5.test;import java.util.Scanner;public class Test1 {/*** param args* 需求&#xff1a;模拟登陆&#xff0c;给三次机会&#xff0c;并提示还有几次* 用户名和密码都是admin* 分析&#xff1a;* 1&#xff0c;模拟登陆&#xff0c;需要键盘录入&#xff0c;…

电商系统的积分(即金币)的设计方案

积分其实就是金币 有些平台把积分和金币拆开独立设计&#xff0c;把金币设计成虚拟货币&#xff0c;而积分可以抵现或者兑换金币&#xff0c;金币可以提现。但是很多平台又将金币和积分的功能合并一起&#xff0c;既可以抵现&#xff0c;又可以提现&#xff0c;而且金币和现金的…

java实现线程的方式_java多线程实现的四种方式

java多线程实现的四种方式1、继承Thread类&#xff0c;重写run方法(其实Thread类本身也实现了Runnable接口)2、实现Runnable接口&#xff0c;重写run方法3、实现Callable接口&#xff0c;重写call方法(有返回值)4、使用线程池(有返回值)1、继承Thread类&#xff0c;重写run方法…

产品经理是如何管理需求

文章目录一、怎么发现需求二、如何判断需求三、定义用户需求四、定义产品需求五、评估产品需求六、管理产品需求一、怎么发现需求 1、什么是需求 特定的人在特定的情况下产生了特定的问题&#xff0c;并且这种问题是可以被解决的&#xff0c;我们就可以把它叫做需求 2、需求从…

spring boot缓存_Spring Boot和缓存抽象

spring boot缓存缓存是大多数应用程序的主要组成部分&#xff0c;只要我们设法避免磁盘访问&#xff0c;缓存就会保持强劲。 Spring对各种配置的缓存提供了强大的支持 。 您可以根据需要简单地开始&#xff0c;然后进行更多可定制的操作。 这将是spring提供的最简单的缓存形式…

有c基础学java多久_有c十十基础的自学java语言每天6小时要多长时间?

建议花6个月学习。1、前面2个月学习下面这本书。2、后面4个月同时学习数据结构与算法 刷LeetCode 学习Spring BootSpring boot 看这本书 官方文档 找点视频看看。Spring Boot provides a variety of features that address todays business needs with a powerful database…

Apache的架构师总结出30条架构设计原则

Srinath是一位科学家&#xff0c;软件架构师&#xff0c;也是一名在分布式系统上工作的程序员。 他是Apache Axis2项目的联合创始人&#xff0c;也是Apache Software基金会的成员。 他是WSO2流处理器&#xff08;wso2.com/analytics&#xff09;的联席架构师。 Srinath撰写了两…

本地运行flowable_在CockroachDB上运行Flowable

本地运行flowable什么是CockroachDB&#xff1f; CockroachDB是一个我一直关注了很长时间的项目。 这是一个开放源代码的Apache 2许可数据库&#xff08; Github链接 &#xff09;&#xff0c;该数据库在很大程度上汲取了Google Spanner白皮书的启发 。 它的核心是可水平扩展的…

win10禁用驱动程序强制签名_图文细说 win10系统未检测到第三个监视器的途径 -win10使用教程...

据统计调查&#xff0c;好多朋友都在为图文细说 win10系统未检测到第三个监视器的途径 的问题而烦恼&#xff0c;小编决定将解决的办法分享给大家。对于电脑菜鸟而言看到图文细说 win10系统未检测到第三个监视器的途径 是很无奈的&#xff0c;试着独自一个人解决图文细说 win10…

HH SaaS电商系统的各种编号(编码/代码/代号)设计

文章目录主订单编号规则一&#xff08;租户内唯一&#xff09;主订单编号规则二&#xff08;租户内唯一&#xff09;子订单编号规则&#xff08;租户内唯一&#xff09;租户编号规则&#xff08;系统内唯一&#xff09;供应商编号规则&#xff08;租户内唯一&#xff09;平台编…

安装openstack_午餐前如何安装OpenStack Cloud

安装openstack图1. QuickStart的内部工作原理 云安装程序 如果我告诉您可以在必须停下来吃午餐之前进行OpenStack Cloud环境设置&#xff0c;该怎么办&#xff1f; 您会感到惊讶吗&#xff1f; 你今天可以做吗&#xff1f; 在大多数情况下&#xff0c;我敢打赌您的答案是不…

5e怎么绑定一键跳投_怎么开通淘宝亲情账号 淘宝亲情账号申请步骤【详解】

据官方消息&#xff0c;淘宝将在2月1日上线“亲情账号”功能。那么 淘宝亲情账号怎么开通?在哪申请? 下面为大家介绍下&#xff0c;一起来看看。亲情账号用户在淘宝账号中可以创建“父亲”或“母亲”角色关系&#xff0c;对父母发出注册邀请或直接绑定他们的账号。完成亲情关…

java redis集群连接池_(08)redis之使用java客户端、spring连接redis、redis集群示例...

一、java代码连接1、新建工程&#xff0c;并引入以下包&#xff1a;jedis-2.7.0.jar、commons-pool2-2.3.jar、junit-4.10.jar2、单实例连接/*** 单实例连接*/Testpublic voidjedisClient(){//创建一个Jedis的连接Jedis jedisnew Jedis("192.168.7.151",6379);//可以…

混合模式商城的可经销商品池

需求背景 自营店铺不允许发布商品 自营店铺的经营模式为“O2O” 自营店铺需开通仓储系统&#xff0c;选售商品后&#xff0c;门店需要自己囤货在仓库&#xff0c;后续在其店铺出售并自行发货出库&#xff0c;若创建的自营店铺未开通仓储系统&#xff0c;选售商品之后&#xf…

探索cqrs和事件源_实践中的事件源和CQRS

探索cqrs和事件源任何尝试实施完全符合ACID的系统的人都知道&#xff0c;您需要做很多事情。 您需要确保可以自由创建&#xff0c;修改和删除数据库实体而不会出错&#xff0c;并且在大多数情况下&#xff0c;解决方案将以性能为代价。 可以用来解决此问题的一种方法是根据一系…

windows功能_你的Windows杀毒软件有这个功能吗?

安全软件首推-火绒&#xff0c;良心之作。比起360安全卫士、腾讯电脑管家&#xff0c;它无广告&#xff0c;无捆绑&#xff0c;无劫持&#xff0c;无弹窗&#xff0c;还免费。我认为最喜人最贴心的功能属它的‘弹窗拦截’了&#xff0c;可以拦截程序推送烦人的弹窗。五大浓缩亮…

base64 二进制流java_读取和base64编码二进制文件

我m trying to read a binary file from the filesystem and then base64 encode it in JavaScript. I使用FileReader API读取数据并找到base64编码器here .我的代码似乎接近工作&#xff0c;问题是生成的base64数据是错误的 . 这是我到目前为止所得到的&#xff1a;function s…

drools dmn_使用Drools的DMN运行时示例

drools dmn正如去年宣布的那样 &#xff0c;Drools 7.0将在合规级别3对DMN模型提供全面的运行时支持。 在撰写本文时&#xff0c;运行时实现已完成&#xff0c;并且该团队现在正在努力进行改进&#xff0c;以进行错误修复和用户友好。 不幸的是&#xff0c;对于7.0版本&#…

笔记本电脑关机后指示灯还亮_汽车仪表常见指示符号之清洗液指示灯,灯亮了怎么办?...

清洗液指示灯就是玻璃水指示灯&#xff0c;用来显示玻璃水的储存量的&#xff0c;平时为熄灭状态&#xff0c;当玻璃水不足时就会点亮提醒驾驶员该添加了。添加后清洗液指示灯还亮的说明出现故障&#xff0c;检查玻璃水电机&#xff0c;相关线路保险丝等&#xff0c;行车中此灯…