更 Groovy 的 Eclipse 体验

工程 | Andy Clement | 2009 年 7 月 30 日 | ...

更新:2009 年 8 月 15 日:评论现已关闭。如果您需要安装帮助、提供反馈或提问,请加入邮件列表档案


在过去的几个月里,SpringSource 一直积极参与开发下一代 Eclipse Groovy Tools。最初的目标是将其从现状发展为一个高度优化的环境,用于代码开发、构建和测试等关键开发任务。理想情况下,使用混合 Groovy/Java 项目时的体验应该与在 Eclipse 中使用纯 Java 项目时一样好。

本周,第一版代码已提交到codehaus仓库,里程碑1即将发布。一个更新站点(适用于Eclipse 3.4.2)已经可用,其中包含当前的开发版本:http://dist.codehaus.org/groovy/distributions/greclipse/snapshot/e3.4 。是的,目前还没有该代码的Eclipse 3.5版本,但很快就会有。(更新!2009年7月31日,Eclipse 3.5更新站点现已在http://dist.codehaus.org/groovy/distributions/greclipse/snapshot/e3.5 上可用)

在本文中,我将简要介绍如何开始使用新插件,然后重点介绍支撑其未来发展的新技术以及它所实现的功能。

入门

从更新站点安装与其他Eclipse功能一样。在Eclipse 3.4.2下,导航到帮助 > 软件更新。在可用软件选项卡上,单击添加站点并输入更新站点URL:http://dist.codehaus.org/groovy/distributions/greclipse/snapshot/e3.4。单击确定。现在,更新站点将显示在列表中,打开它并标记“Groovy-Eclipse插件”条目。最后,在右上角,单击安装并按照对话框完成安装。安装后,有三种方法可以开始您的工作:
  1. 创建一个新的Groovy项目。就像您可以创建Java项目一样,有一个Groovy项目创建向导。所有Groovy项目都实际支持.java和.groovy文件的混合。
  2. 修改现有的Java项目,以便您可以包含Groovy代码。在包资源管理器中选择您的Java项目,右键单击并导航到上下文菜单中的Groovy,然后选择添加Groovy特性。完成后,您的项目图标将更改,此后该项目中的任何.groovy文件(除了.java文件)都将构建。
  3. 迁移现有的Groovy项目。如果您有使用旧版本插件创建的Groovy项目,则必须将其迁移到新版本。要迁移项目,请选择要迁移的项目,然后右键单击并导航到Groovy,然后选择转换旧版Groovy项目。此选项仅在所选项目需要迁移时才出现。
就是这样!只需开始创建Groovy类型并像使用Java一样使用它们。常见问题解答http://groovy.codehaus.org/Eclipse+Plugin+V2+FAQ试图回答我们认为关于此Alpha版本常见的疑问,并包含指向何处提出遇到的任何问题或您想提出的其他问题的链接。

现有插件编译策略

在描述此版本使用的新编译器技术之前,值得简要介绍一下现有版本使用的技术。当前发布的Groovy Eclipse插件利用了现有的Groovy编译器“联合编译”支持。联合编译允许构建混合Java/Groovy代码库,其中Java和Groovy类型之间存在引用。它主要按以下方式工作:
  • 让Groovy编译器 (groovyc) 解析 .groovy 文件
  • 在磁盘上创建存根,这些存根是这些Groovy文件的类似Java的表示。
  • 调用javac来构建.java文件,这些文件能够通过存根查看Groovy文件。
  • 完成Groovy文件的处理——现在可以解析对Java类型 .class 文件的引用。
最终用户的所有源文件都构建成了二进制 .class 文件。

简化项目构建策略

我知道有些用户,包括我自己,在设置项目以使用联合编译的eclipse插件版本进行构建时遇到了麻烦——它使用的双重构建器设置可能难以正确配置。当我们着手设计工具的下一版本时,我想知道是否有一种更优化的方法,只由一个构建器负责,并且它知道何时调用Java或Groovy文件。拥有一个构建器将消除配置项目构建的任何复杂性。

我的初步想法是,Eclipse编译器应该负责构建代码,但在必要时应让groovyc参与处理任何groovy代码。由于我在编译器方面的背景(从事AspectJ),我已经非常了解Eclipse Java编译器。然后,在与Jochen Theodorou(groovy技术主管)讨论groovyc编译器的结构后,看起来可以在Eclipse编译器和groovyc之间实现更紧密的集成,避免使用存根。在正常的联合编译中,磁盘上的存根本质上是groovyc告诉javac它在做什么的一种方式,类似地,javac生成的.class文件是javac告诉groovyc它刚刚做过什么的一种方式。优化编译器之间的通信将仅仅意味着它们直接对话,而不是通过磁盘上的文件(存根.java文件或.class文件)。然而,编译器通信方式的任何改变都不得影响现有联合编译策略提供的最重要的功能——它允许在两种语言定义的类型之间自由引用。举个例子,考虑在一个项目中定义的这三种类型:

hierarchy

“什么应该首先完全编译?”没有正确的答案。如果Groovy代码首先全部编译,它将无法找到Apple Java类型。如果Java代码首先编译,它将无法找到Fruit Groovy类型。显然,当将Eclipse编译器和groovyc结合在一起时,它们需要在整个编译过程中相互了解,并能够相互提问(最重要的是:你能解析这个类型吗?)。为了支持这种方法,可能需要对双方,即Eclipse编译器和groovyc进行更改,但会注意尽量减少这些更改,并且希望这些更改能够贡献回两个编译器项目。

除了“简单任务”将两个编译器粘合在一起之外,新版本还有一些额外的要求:

  • 使Eclipse为Java提供的增量编译行为适用于Groovy代码。
  • 在任何情况下都不能改变Eclipse编译器构建纯Java项目的方式。它必须像以往一样快速可靠。
  • 尽量避免在Eclipse编译器中引入任何特定于groovy的依赖项。相反,使用抽象并扩展Eclipse以支持“某种其他语言”,在这种情况下,首次将是groovy。
实现后一个目标将使我们处于将Eclipse编译器更改贡献回Eclipse的有利位置。

不只关于性能

当然,优化编译器之间的通信应该可以提高性能,让Groovy的增量编译工作起来会很棒,但还有另一个很好的理由来采用这种以Eclipse编译器为主导的新单一构建器策略。如果能让Eclipse更好地理解groovy,那么Eclipse的一些功能就会“自然而然地”工作。一个很好的例子就是JUnit支持。为了在Eclipse中运行测试用例,您通常使用上下文菜单运行方式 > JUnit或快捷键Alt+Shift+X, T。在当前版本的groovy插件中,这行不通,Eclipse不知道编辑器中显示的是什么。在新的世界中,编译器之间的集成层使Eclipse能够理解groovy文件中的结构——它可以看到测试类,可以看到任何@Test注解,甚至可以看到任何@RunWith注解来选择测试运行器。因此,JUnit启动就能正常工作。这只是零努力就能实现的众多功能之一。这里重要的是要理解,Eclipse编译器并非直接修改来处理groovy代码,它始终将groovy代码的处理委托给groovy编译器,但编译器之间的集成层使Eclipse能够理解groovyc调用的结果。

内部结构

在短时间内实现集成层的原因是两个编译器现有的灵活结构。在Eclipse编译器中,编译的各个阶段清晰可见且易于访问,而在groovyc中甚至更清晰(它们被称为阶段)。将编译器集成在一起,基本上就是定义一个流程,协调和控制每个编译器通过各个阶段/阶段的进展。尽管实际编译中有很多阶段,但为了理解新设计,可以将其视为一个简单的三阶段过程:解析/解析/生成。

解析阶段,输入数据从纯文本形式处理成某种内部数据结构——不对该结构进行任何推断。

解析阶段,结构中按名称引用的实际实体被追查。例如,如果源中使用“Foo”,则必须确定用户指的是哪个Foo——这通过适当的解析规则完成:我的导入是什么?此包中有什么?类路径上有什么?在groovy情况下,还有额外的规则,例如:我的别名导入是什么?

生成阶段,实际的 .class 文件被创建。

下图显示了新构建器在被调用编译项目时的架构。所有源文件(包括.java和.groovy)都传递给Eclipse编译器。根据文件扩展名,Eclipse编译器要么自己解析文件,要么请求groovyc解析文件。完成后,解析会在所有已发现的类型(Groovy和Java类型)之间运行。两个编译器中的解析策略都经过调整,以便它们可以相互看到对方的类型。最后,在解析后,生成阶段运行以创建.class文件。

[caption id="attachment_2593" align="aligncenter" width="624" caption="新编译系统的结构"]新编译系统的结构[/caption]

通常,在生成.class文件后,Groovy编译过程会立即将文件写入磁盘,但在新设计中,它们被返回给Eclipse编译器。这最后一步使增量编译得以实现。Eclipse分析groovyc生成的类文件,就像它自己创建的类文件一样。类之间的引用信息以与常规Java类型使用的完全相同的结构保留——这使我们“免费”获得了Groovy的增量编译支持。由于此引用信息以与Java类型相同的方式保留,因此它会自动为每个项目在Eclipse重启后持久化,并且其他依赖项目也可以利用它。后两个功能对于AspectJ来说仍然是一个问题,因为AspectJ对Eclipse编译器的修改采用了不同的方法。

增量编译

这本身就值得一篇完整的博客文章,但这里值得描述其基本原理。编译后,Eclipse编译器会记录它处理的所有类型之间的引用。增量编译无非是在构建某个内容后查阅引用列表,以查看哪些内容受更改影响。如果没有受影响,则编译结束。如果某些类型确实依赖于刚刚构建的内容,则它们会被编译。这里描述的机制甚至可以为纯Groovy项目提供增量编译。

意外的奖励?

很早就发现,由于Eclipse现在可以看到Groovy类型的类似Java的结构,它会检查该结构。对于Groovy代码,某些检查无效,因为Groovy在允许的方面更灵活,但有些检查很有用。考虑一下,如果代码在利用泛型方面不太正确,Eclipse编译器会报告无尽的(可配置的)与泛型相关的警告。此屏幕截图显示Eclipse编译器实际上正在检查Groovy代码。

[caption id="attachment_2594" align="aligncenter" width="708" caption="Groovy代码的泛型警告"]Groovy代码的泛型警告[/caption]

这些检查的价值仍在讨论中,但目前它们仍处于激活状态。

用户界面

我刚才谈论的所有内容都是底层的编译策略。在Eclipse UI中,它仅表现为用于编译混合Java/Groovy项目的“构建器”。在此之上,Andrew Eisenberg(也和我一起在温哥华SpringSource实验室)一直在为UI注入活力:
  • 将现有插件中在新环境中仍然需要的组件移植过来(并进行演进),将它们重新基于新的编译基础设施。
  • 开发/增强用户在IDE中依赖的那些功能:编辑器、大纲视图、代码辅助、导航、调试等。
最终结果是,Eclipse UI在处理Groovy时看起来和行为都与处理Java时完全一样。这是来自Spock测试框架(http://code.google.com/p/spock/)的PublisherSubscriberSpecification示例。它可以直接作为JUnit测试执行。

[caption id="attachment_2595" align="aligncenter" width="1088" caption="执行Spock示例"]执行Spock示例[/caption]

是的,对于那些“内行”的人来说,这张截图确实表明这个新的构建器支持Groovy AST转换,因为Spock就是这样实现的。

在IDE之外

我知道许多人将Eclipse编译器作为其构建系统中的Java编译器。这让他们对构建系统正在做的事情更有信心,因为它是他们IDE中使用的同一个编译器。本文中描述的集成Eclipse/Groovy编译器可以以类似的方式使用,无论是直接在命令行还是通过Ant。最终发布时,我们将提供有关如何执行此操作的文档。

Alpha版本

目前所有工作的成果均可下载。下载内容包括一个用于Eclipse JDT编译器的补丁,用于暴露适当的扩展点,一个略微修改的Groovy 1.7构建,将它们连接在一起的集成代码,以及最后提供UI的其他插件。

它运行得如何?这是一个里程碑1之前的版本,所以请理解它还不是生产就绪版本!定义Groovy和Java类型之间交互的方式太多了,尽管已经测试了许多,但您第一次尝试的东西可能会把它弄坏!我们恳请您通过报告任何问题来帮助我们,以便在我们走向第一个版本时提高质量。常见问题解答在http://groovy.codehaus.org/Eclipse+Plugin+V2+FAQ提供了更多信息,包括提出问题和报告问题的链接。目前唯一可用的下载版本是针对Eclipse 3.4.2的。Eclipse 3.5支持将很快推出。最近的重点是编译和增量编译。我们知道UI的某些部分仍然有点迟钝(例如代码辅助),并将积极努力加快这些速度,常见问题解答讨论了造成这种情况的原因。

未来

第一个采用这种新编译器技术的Eclipse插件版本旨在提供最小化且一致的功能集,同时为用户提供价值,因此其主题是提供优化的编辑/保存/编译/测试体验。我们认为第一个版本可以在几个月内发布。在即将发布的第一个里程碑版本之后,我们将积极提供更频繁的开发版本,以迈向M2和最终版本。其中甚至可能包含一些与Grails相关的功能。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单的订阅。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看所有