写代码的代码:JET

用过EMF的人想必都对它的代码生成功能印象深刻吧,有没有想过这是怎样实现的呢?

代码生成一般是通过写好的模板,在用户输入一些限制条件后,由程序把这两者结合起来得到需要的代码。EMF也是这样,它内置了一些模板(放在 org.eclipse.emf.codegen.ecore里),我们通过Java Interface或XML Schema文件建立ecore模型后(这一步由org.eclipse.emf.codegen.ui支持),插件 org.eclipse.emf.codegen帮我们生成model、edit、editor和test这几个新的插件,这些生成的插件就可以被用来构 造应用程序了。

EMF使用JET(Java Emitter Templates)进行代码生成,JET使用的模板文件与JSP格式几乎完全一致,像JSP里有application这样的隐含变量一样,在JET模 板文件里可以使用argument这个隐含变量,它代表用户的输入参数(对EMF来说就是ecore模型)。下面是一个最简单的带有参数的模板文件 hello.txtjet,JET模板文件的扩展名一般是要生成文件类型再加上jet。

<%@ jet package="hello" class="GreetingTemplate" %>
Hello, <%=argument%>!

只要给这个模板文件一个参数,JET就能帮我们生成一个字符串,其内容是“Hello,参数!”。如果我们定义一个.javajet的模板,配合适当的参数,再把生成的字符串保存为文件,就得到了java代码,EMF的代码生成过程就是如此。

自己实现代码生成器的过程如下:创建一个Plugin项目,编写模板文件.javajet,一般放在templates目录下;定义元模型,这个元 模型要与模板相匹配,模板的argument一般就是元模型最外层的container;构造一个用户界面,让用户可以构造元模型的实例;提供一个 Action比如按钮,用户按下即开始生成代码。

代码的生成是由JETEmitter完成的,它会在workbench里先生成一个.JETEmitter项目,把模板转换为java类(这个过程类似JSP转换为Servlet),然后调用这些类的generate()方法得到结果。

我做了一个生成.txt文件的生成器插件,点此下载。安装后在Eclipse主菜单里选File->New->Others,在New对话框里选择Sample Wizards下的Echo filename text file,新建的文本文件内容里会包含文件名。

因为用途有限,JET的资料不是很多,这里有两篇:链接1链接2,其中后者在EMF的帮助里也找得到。

最后补充一个Tip,在plugin里访问一个相对路径文件的方法如下:

String base = Platform.getBundle(pluginId).getEntry("/").toString();
String relativeUri = "templates/echo.txtjet";
JETEmitter emitter = new JETEmitter(base + relativeUri, getClass().getClassLoader());

更正(08/23),上面说的方法只对JETEmitter有效,得到的路径是Platform内部路径而非本地路径,这里提供另一个方式可以得到本地路径:

Platform.asLocalURL(Platform.getBundle(pluginId).getEntry("/log4j.properties"))

 

感受Ruby on Rails

最近看到几篇介绍Ruby on Rails(RoR)的文章,忍不住自己也下载了一份来体验一下,简单说说感受。

参考文档建立了一个很简单的系统,没花多少时间,这主要归功于scaffold函数提供了缺省的web界面。要想修改这个界面却不那么简单,配置上只要修改一两处,但必须手写一个.rhtml模板文件,这里面存在不少代码,而且ruby代码和html代码交叉得很厉害,和asp差不太多。当然,我想这一步是使用任何框架都无法避免的,看到有文章说RoR的开发效率是struts的十倍,我保留意见。

RoR另一个提高开发效率的途径是做了很多假设来代替配置文件,例如控制文件都放在controller目录里,模型文件都放model目录,url映射就是控制文件名的前半部分,数据库表名与model的对应,等等。我很赞同这种方式,一是节约了写一堆xml配置文件的时间,二是任何熟悉RoR的人都能很快找到需要的类。

由于对Ruby并不熟悉,所以我看.rb文件里的代码会比较吃力。Ruby是解释型的语言,它在语法上有一些方便之处,例如变量的表示;而且它是比较彻底的面向对象语言,连数字123都是对象;三是省略了编译这个步骤,源代码修改后可以立即生效(Eclipse的增量编译基本上也可以达到这个效果);缺点应该是主要是性能方面,我想很可能比不上jsp。

长时间使用一种语言后,总想偶尔换换口味。Java是我最喜欢的无疑,同时也很羡慕掌握多门语言的高手,碰到问题先考虑用哪种语言实现,毕竟每门语言都有自己擅长。继续研究研究Ruby,也许它会成为我的另一杆枪。

另外,RDT是一个Ruby开发的Eclipse插件,但对RoR似乎没有特别的支持。除了.rb文件的编辑器外,它还专门集成了一个正则表达式验证工具,看来Ruby在这方面也比较在行。