概述
本系列文章的 前一篇介绍了有关 Eclipse 的 Java Emitter Templates (JET)和代码生成的知识,在那篇文章中,您已经看到如何通过使用模板和代码生成器 来节省时间,并实现模式级的代码重用。然而在大部分情况中,这都还不够。您需要能够 将所生成的代码插入现有的代码中,或者允许以后的开发人员来定制所生成的代码,而不 需要在重新生成代码时重新编写任何内容。理想情况下,代码生成器的创建者希望可以支 持今后开发人员所有的需求:从修改方法的实现、修改各种方法签名,到修改所生成类的 继承结构。这是一个非常有趣的问题,目前还没有很好的通用解决方案;但是有一个很好 的纯 Java 的解决方案,称为 JMerge。
JMerge 是 EMF 中包含的一个开放源代码的工具,可以让您定制所生成的模型和编辑 器,而重新生成的代码不会损坏已经修改过的内容。如果描述了如何将新生成的代码合并 到现有定制过的代码中,那么 JETEmitter 就可以支持 JMerge。本文通过一个例子来展 示其中的一些可用选项。
第一步
假设您已经添加了一个新项目,在这个项 目中需要为编写的每个类都创建一个 JUnit 测试类,这样必须要对编写的每个方法都进 行测试。作为一个认真且高效的(或者比较懒的)程序员来说,您决定要编写一个插件, 它接受一个 Java 类作为输入,并生成 JUnit 测试例子的存根(stub)。您热情高涨地 创建了 JET 和插件,现在想允许用户定制所生成的测试类;然而在原有类的接口发生变 化时,仍然需要重新生成代码。要实现这种功能,可以使用 JMerge。
从插件中调 用 JMerge 的代码非常简单(参见清单 1)。这会创建一个新的 JMerger 实例,以及一 个 URI merge.xml,设置要合并的来源和目标,并调用 merger.merge() 。然后合并的内 容就可以展开为 merger.getTargetCompilationUnit() 。
清单 1. 调用 JMerge
// ...
JMerger merger = getJMerger();
// set source
merger.setSourceCompilationUnit(
merger.createCompilationUnitForContents(generated));
// set target
merger.setTargetCompilationUnit(
merger.createCompilationUnitForInputStream(
new FileInputStream (target.getLocation().toFile())));
// merge source and target
merger.merge();
// extract merged contents
InputStream mergedContents = new ByteArrayInputStream(
merger.getTargetCompilationUnit().getContents().getBytes());
// overwrite the target with the merged contents
target.setContents (mergedContents, true, false, monitor);
// ...
// ...
private JMerger getJMerger() {
// build URI for merge document
String uri =
Platform.getPlugin (PLUGIN_ID).getDescriptor().getInstallURL().toString();
uri += "templates/merge.xml";
JMerger jmerger = new JMerger();
JControlModel controlModel = new JControlModel( uri );
jmerger.setControlModel( controlModel );
return jmerger;
}