利用EMF举办元建模:生成详细、可重用的Java代码片断
副标题#e#
EMF 是 Eclipse 平台的主要部门,而且是一些相关技能和框架的基本,好比 Eclipse Visual Editor、SDO、XSD 和 UML — 个中的很多技能都被集成到 Rational® Application Developer 和 WebSphere® Business Modeler 等 IBM® 平台中。此刻,EMF 已经接收了很多 Java 技能特性,好比列举范例、注释和泛型。
在大大都文档和教程中,EMF 都被用于建模数据 和接口(好比 EMF 刊行文档中的 Library 和 Books),而不消于建模行为。虽然,尚有一些针对数据工具生成的默认要领实现,但这些实现涉及到模子元素之间的干系。并且,将 EMF 用作 “元模子” 的颠末归档的示例很是少 — 除了 Eclipse Foundation 文章 “Modeling Rule-Based Systems with EMF”— 可是这个示例并没有展示如何扩展 Ecore 元模子。
最后,利用和扩展 EMF JET 模板的进程也没有被很好地举办归档。另外,JET Editor 项目最近已经迁移到另一个 Eclipse 项目(M2T)上。本文旨在澄清这些问题,并使您可以或许在 EMF 上下文中利用动态模板实现更多的成果。因此,本文假设您对 EMF 有根基的相识。
为什么要扩展 Ecore 元模子?
Ecore 毕竟是什么?
Eclipse Modeling Framework (EMF) 是 Eclipse 的一个建模框架。按照 Eclipse Foundation 的界说,焦点 EMF 框架包罗一个描写模子的元模子(Ecore)和模子的运行时支持,包罗变动通知、对默认 XMI 序列化的耐久性支持和用于对 EMF 工具执行通例操纵的反射 API(reflective API)。换句话说,Ecore 界说焦点模子的布局,而焦点模子界说开拓人员用于维护应用措施数据的模子布局。
Ecore 元模子是一个强大的东西,可用于设计模子驱动架构(Model-Driven Architecture,MDA),后者可以作为软件开拓的起点。凡是环境下,我们界说应用措施范畴内的工具(EClass 范例)、工具属性以及它们之间的干系。我们还利用 EOperation 模子元素界说属于这些工具的特定操纵。默认环境下,EMF 将会为这些操纵生成骨架 或要领签名,可是我们必需返回并实现这些操纵,经常要重复地从头编写雷同的逻辑。
可是,假如我们想在模子中指定某种任意的实现行为该怎么办呢?一种要领是添加基于文本的注释(EAnnotation 范例),以建模工具并在代码生成期间表明模板中的这些注释。关于这种要领的精彩示例,可以查阅 Eclipse Foundation 文章 “Implementing Model Integrity in EMF with MDT OCL”。可是,正如这篇文章中所描写的,我们的方针不是验证模子元素,而是对实现自己举办建模,以使任何详细的模子可以或许重用这些元模子元素。为此,我们需要扩展 Ecore 元模子。
扩展了的元模子
本文附带了一个高度简化的用来扩展 Ecore 的编程式模子。它不是一个完整或连贯的元模子或框架;严格来讲,它是一个元素的原型荟萃,用于演示利用 EMF 对代码实现举办元建模的本领。图 1 显示了我们的扩展元模子示例 EcoreX 的快照,下面是每个元素的简短描写。
图 1. EcoreX 模子
EcoreX 元素
EPackageX 扩展 EPackage
这是 Ecore 元素 EPackage 的一个简朴 “标志” 扩展,没有任何附加属性。这个元素是必须的,因为在默认环境下,元素 EPackage EMF 编辑器插件不答允将 EClass 的子类作为子元素添加(参阅下面的 EClassX)。通过提供一个可扩展 EPackage 的模子元素,代码将会自动生成,从而答允将一个 EClassX 子元素添加到 EPackageX 中。
#p#副标题#e#
EClassX 扩展 EClass
同样地,这是 Ecore 元素 EClass 的一个简朴标志扩展,没有任何附加属性。与上面的元素雷同,此元素也是必须的,因为在默认环境下,EClass 的编辑器插件不答允添加 EOperation 的子类 — 这正是我们要在本文中实现的方针。
EOperationImpl 扩展 EOperation
这是用于向 Ecore 模子添加详细的元成果的根基实体和进口点。此元素被赋予 Ecore 的基本 EOperation 元素中没有的属性。下面描写的所有其他元素都属于 EOperationImpl 并用于组成编程式实现。譬喻,EOperationImpl 包括变量和语句,可以返回一个引用或值。
LocalVariable 扩展 ETypedElement
LocalVariable
是一个当地变量。变量包括一个名称和一个 Java 范例(好比 String、Integer、Object),并且由于这些属性已经存在于其超等超类(super-superclass)EParameter 中,所以 LocalVariable 不需要特别属性。
Statement 扩展 EClass
在我们的简化逻辑模子中,一个 EOperationImpl 包括很多将会按给定顺序计较的 statement。Statement 是一个抽象超类。
#p#分页标题#e#
LiteralAssignment 扩展 Statement
LiteralAssignment 引用一个变量,而且有一个 String 属性,答允用户输入一个要被理会的值并将其分派给一个变量(譬喻,“hello”、“4.5” 可以别离分派给 String 或 float)。
Access 扩展Statement
Access 暗示引用 Java 字段或操纵的行动。
FieldReferenceAssignment 扩展 Access
会见一个字段,以分派一个值(譬喻,var1 = var2.name)。
Invoke 扩展 Access
挪用一个操纵(Java 要领)。Invoke 的功效可以分派给一个变量(譬喻,myVar = obj.toString())。
图 2 展示了 EcoreX 元模子的一种越发雷同 UML 的暗示。
图 2. Ecorex 模子图
入门
本文包罗六个高级的步调:
扩展 Ecore 元模子,添加新语义
为被扩展的元模子建设一个 genmodel。
为此元模子生成一个 EMF 编辑器,并作为插件安装。
利用这个新编辑器,构建一个详细的模子来描写编程行为。
为这个详细的模子建设并设置一个 genmodel。
基于这个详细的模子生成详细的 Java 代码。
可以建设或导入上面描写的元模子。两种环境都需要从一个现有 EMF 项目或建设一个新项目入手(New > Other > Eclipse Modeling Framework > Empty EMF Project)。我们的项目名为 EMFX,而且它应包括一个名为 model 的文件夹。可以将这个 EcoreX.ecore 模子复制到 model 目次并跳至 构建和启动 Editor Metamodel 插件 小节,也可以执行以下步调,从新建设一个元模子。
扩展 Ecore 元模子 — 从新开始
右键单击项目,从上下文菜单中选择 New > Other > Example EMF Model Creation Wizards > Ecore Model。(对付 Eclipse V3.5+ [Galileo, Helios],则应选择 New > Other > Eclipse Modeling Framework > Ecore Model。)选择 model 文件夹和名称 EcoreX.ecore。
默认环境下,我们将模子包称为 ecorex。在模子窗口中右键单击并选择 Load Resource > Browse Registered Packages。选择具有名称空间 http://www.eclipse.org/emf/2002/Ecore 的 Ecore Model。
导入 Ecore 元模子之后,就可以对其举办扩展了。要从头建设 ecorex.ecore 模子,首先在包元素 ecorex 上右键单击并选择 New Child EClass。将此元素称为 EPackageX(参阅上面的模子元素描写)。然后需要将基元素 EPackage 作为这个新元素的 ESuper Type 添加。
通过将 EClass 指定为 ESuperType,利用沟通的进程建设新元素 EClassX。按照需要对 Ecore 工具分别子类,在 EcoreX 模子中继承界说其他 EClass。利用图 1 和 EcoreX.ecore 文件相识要为哪个 EClass 建设什么属性。
构建并启动 the Editor Metamodel 插件
I在构建步调中,我们将建设元模子 genmodel 并构建模子和编辑器项目。右键单击 EcoreX 项目并选择 New > Other > Eclipse Modeling Framework > EMF Model。(对付 EMF V2.5+ [Galileo, Helios],则应选择 New > Other > Eclipse Modeling Framework > EMF Generator Model。)可以提供一个名称或接管默认的名称 EcoreX.genmodel。EcoreX 模子应该被预选择为 genmodel 的基模子。单击 Load 验证 EcoreX.ecore 元模子。
图 3. 新 EMF 模子
当要求指定要生成和从其他生成器模子引用的包时,选择 Root packages 下面的 EcoreX 包和 Referenced generator models 下面的 Ecore。
此刻,领导将为元模子建设一个 genmodel。突出显示 genmodel 中的顶级元素之后,从上下文菜单中选择 Generate All,这样可以自动生成关联的代码。按照在 genmodel 中设置的行为,这将生成 4 个 Eclipse 项目。本文不会存眷 .test 项目,所以您大概不但愿生成这个插件。
此刻我们继承启动步调。在大大都 Eclipse 教程中,城市要求您在单独的 Eclipse 进程中启动所开拓的插件。在本节中,我们将回收一种差异的要领:我们将在当前 Eclipse 和事情区中激活插件。这样更容易将预构建的元模子与下一节中详细的模子开拓集成。为此:
双击 EMFX plugin.xml 打开插件设置编辑器。
单击 Exporting 选项卡下的 Export Wizard。
选择根基的建模插件和两个编辑器插件。
在 Destination 选项卡下,选择 Eclipse 安装目次,或托管存储库(假如可用)。
图 4. 导出
留意:假如利用 –console 选项启动 Eclipse,您可以利用 OSGi 呼吁节制台动态地启动、遏制、更新和刷新插件(插件组),无需从头启动 Eclipse 或启动一个单独的实例。
#p#分页标题#e#
单击 Finish 时,会自动构建生成的插件 JAR 文件,并自动将其复制到插件目次。此时,您需要从头启动 Eclipse,激活新插件。此刻我们已经筹备好启动编辑器插件了,建设一个新项目来生存我们的详细模子(我们的模子定名为 Test2)。
在这个新项目中,导航到 New > Other Example EMF Model Creation Wizards > Ecorex Model 并提供一个模子名称。留意:在 EMF 的最新版本 (V2.5+) 中,详细模子的文件扩展名必需被设为 .ecore,而不是 .ecorex;不然,这个详细的 genmodel 将不能在后续步调中被乐成建设。选择 EPackageX 元素。您此刻有了一个空的详细模子。后续小节将接头如何构建这些编程模子元素;完成后的文件 My.ecore 可以在 参考资料 部门找到。
建模详细的测试模子
在本节中,我们将对一个详细的 Java 类(EClassX 的实例)举办建模,这个类包括两个详细的要领,我们将对这两个要领的实现举办建模。第一个示例要领接管 String 参数动静,并输出动静和一个时间戳 — 这有利于调试动静。以下是期望功效的暗示。
清单 1. printTimestampMessage
void printTimestampMessage(String message) {
System.out.print(message);
System.out.print("; Timestamp= ");
System.out.println(System.currentTimeMillis());
}
第二个示例接管 3 个基于日期的参数,并返回一个数字值,暗示该日期对应的是礼拜几。
清单 2. getDayOfWeek
int getDayOfWeek(int year, int month, int date) {
int result;
Calendar calendar = Calendar.getInstance();
calendar.set(year, month, date);
result = calendar.get(Calendar.DAY_OF_WEEK);
return result;
}
第一步是填入在上一节最后一步中建设的新 EPackageX 元素下的 3 个必须属性。假如在建模窗口下看不到 Properties 选项卡,可以从上下文菜单中选择 Show Properties View。在这个示例中,我们的包名为 mypackage。
图 5. EPackageX 属性
接下来,向 mypackage 添加一个新 EClassX。可以在 mypackage 突出显示时利用上下文菜单完成此任务。填入 name 属性,为类提供一个名称(好比 MyClass),向新类添加两个 EOperationImpl 元素,并为它们指定要领名 printTimeStampMessage 和 getDayofWeek。然后,向每一个操纵添加 Ecore 参数。
图 6. EOperationImpl getDayOfWeek()
图 7. getDayOfWeek() 属性
上面的操纵 printTimestampMessage() 接管一个 EString 范例的参数,而 getDayOfWeek() 接管 3 个 EInt 范例的参数。另外,操纵 getDayOfWeek 返回一个 EInt,这可以在 property 属性 EType 下举办设置(拜见图 7)。
分解 EOperationImpl
到此刻为止,我们仅利用了担任的 Ecore 元素和属性。此刻是时候利用我们扩展的元模子元素来构建 Java 实现了。
LocalVariable
查察一下图 8,printTimestampMessage() 将需要两个 LocalVariable 元素 — 一个为 EString 范例,另一个为 ELong 范例。
图 8. printTimestampMessage()
图 9. LiteralAssignment
在图 9 中,Value 属性的字符串被内联到 LiteralAssignment。您可以设想一个差异的元模子,个中的文字值(常量)被建模为单独的元素。
接下来,我们插入一个 LiteralAssignment 范例的元素,它答允选择一个 LocalVariable 并为其分派值。在本例中,我们选择 String 变量并提供上面的原型要领中的文本值(记着在文本双方加上引号)。
DataType
再次查察上图,留意,有一个名为 SystemType 的 Ecore DataType,它是 java.lang.System 的一个包装器。必需将其添加到我们的 mypackage 包,因为它将会被随后的 Invoke 元素引用。
Statement
添加到这个操纵的第一个 Statement 是 SystemType 中的静态要领 currentTimeMillis() 的一个 Invoke,已经在上面界说了。
图 10. 挪用 currentTimeMillis() 属性
按照我们的元模子(我们将在下一节提供代码模板),上面的 Invoke 将转换为 Java 语句:timestamp = java.lang.System.currentTimeMillis();。
下一个 Invoke 与之前的谁人稍有差异。首先,没有 Assignment。其次,我们将把 message 参数的引用作为 Args 属性的一个参数。
图 11. 挪用 out.print 属性
操纵中的第 3 个(最后一个)Invoke 是一个利用 LocalVariabletimestamp 作为单个参数的 println()。这就完成了详细操纵 printTimestampMessage() 的建模。
让我们看看第二个 EOperationImplgetDayOfWeek() 的完整模子。
图 12. getDayOfWeek()
DataTypes
在模子的底部,我们建设了一个特另外 DataType,名为 CalendarType,这是该操纵所必须的。
LocalVariables
#p#分页标题#e#
在操纵模子的 3 个 LocalVariable 中,我们主要存眷称为 result 的 LocalVariable,因为它将会生存执行完操纵的最后一条语句之后返回的值。在 EOperationImpl 属性中有一个名为 Return Ref 的属性,并且在我们的实现中,我们利用下拉菜单选择 LocalVariable 功效。
Statement
正如图 12 所示,3 个 LocalVariable 之后是 3 个 Statement。第一个是 Invoke,它利用 CalendarType 元素上的 getInstance(),为 calendar 变量分派一个值,与图 10 中的操纵雷同。
接下来是对 calendar 变量执行的 set() 要领的 Invoke,此刻它通报 3 个与 EOperationImpl 参数(year、month 和 date)相对应的 Arg。
图 13. 带有参数的 set()
图 14. FieldReferenceAssignment
按照我们的元模子,这个元素将会生成与 DAY = Calendar.DAY_OF_WEEK; 雷同的 Java 代码。
在图 15 中,DAY 变量用于这个 EOperationImpl 的最后一个 Invoke:一个 get(),其返回值被分派给变量 result(我们的实现的 Return Ref)
图 15. Return Ref
实现动态模板
我们此刻设计了一个扩展的元模子,并用其描写了一个详细的模子 My.ecore(请拜见上述的 EMF V2.5+ 文件名称说明)。此刻终于可以用 JET 最终实现一些代码实现了。要查察 JET 模板的语法突出显示成果,您需要安装 JET Editor Plugin。
默认环境下,在为模子生成代码时,EMF 不会利用动态模板。它利用预构建的 Java 类。要开始定制 JET 模板,我们需要从插件 JAR 文件 org.eclipse.emf.codegen.ecore_2.3.0.XYZ.jar 复制一些文件,个中 XYZ 是 Eclipse 插件文件夹中您的 EMF 版本的时间戳。本文利用 org.eclipse.emf.codegen.ecore_2.3.0.v200706262000.jar。要复制这些文件,请利用任意一种解压缩东西打开 JAR 文件,并执行以下操纵:
从这个 JAR 文件将模板目次提取到您的详细模子的 Java 项目中。
在模板/模子中建设一个目次,名为 Class。
在 Class 文件夹中建设一个新的空文件,名为 implementedGenOperation.TODO.override.javajetinc 。
由名称可以看出,第 3 步中的新文件是一个 JET 模板,我们将在个中插手模子工具 EOperationImpl 的代码生成逻辑。默认环境下,这个文件并不存在,因为 EMF 只为每个 EOperation 提供一个空的要领签名。一旦激活了动态模板成果,我们的新文件将被作为 Java 要领体自动包罗,正如 EOperationImpl 所界说的。
以下是 implementedGenOperation.TODO.override.javajetinc 的完整代码。
清单 3. implementedGenOperation
// created by implementedGenOperation.TODO.override.javajetinc ><% >if ( ! (genOperation.getEcoreOperation() instanceof EOperationImpl) ) { %> > // TODO: implement this method > // Ensure that you remove @generated or mark it @generated NOT > throw > new UnsupportedOperationException(); ><% } else { %> > // ** EOperationX implementation ** ><% EOperationImpl opx = (EOperationImpl)genOperation.getEcoreOperation(); >Statement stm = null; >Iterator iterator = null; >EList<LocalVariable> pList = opx.getLocalVariables(); >LocalVariable lvar = null; >String iname = null; >StringBuffer paramsString = null; >StringBuffer varString = null; >for (int i = 0;i < pList.size(); i++) { > lvar = pList.get(i); > iname = lvar.getEType().getInstanceClassName();%> > <%=iname%> > <%=lvar.getName()%><% > if (iname.startsWith("java")) { %> = null > <% } %>; ><% } >iterator = opx.getStatements().iterator(); >while (iterator.hasNext()) { > paramsString = new StringBuffer(); > varString = new StringBuffer(); > iname = null; > stm = (Statement)iterator.next(); > if (stm instanceof LiteralAssignment) {%> > <%= stm.getAssignment().getName()%> = <%=\ >((LiteralAssignment)stm).getValue()%>; > <%} else > // > if (stm instanceof FieldReferenceAssignment) { > Access ax = (Access)stm; > if (stm.getAssignment() != null) { > varString.append(stm.getAssignment().getName()); > varString.append(" = "); > } > if ( ax.getStaticType() != null) { > // STATIC > iname = ax.getStaticType().getInstanceClassName(); > } else { > // NON STATIC > iname = ax.getTarget().getName(); > } %> > <%=varString.toString()%><%=iname%>.<%=ax.getAccessName()%>; > <% } else > if (stm instanceof Invoke) { > // INVOKE > Invoke iv = ((Invoke)stm); > if (stm.getAssignment() != null) { > varString.append(stm.getAssignment().getName()); > varString.append(" = "); > } > for (int p = 0; p < iv.getArgs().size(); p++) {\ >paramsString.append(iv.getArgs().get(p).getName()); > if ( p + 1 < iv.getArgs().size() ) { > paramsString.append(" , "); > } > } > if (iv.getStaticType() != null) { > // STATIC > iname = iv.getStaticType().getInstanceClassName(); > } else { > // NON STATIC > iname = iv.getTarget().getName(); > } %> > <%=varString.toString()%><%=iname%>.<%=iv.getAccessName()\ >%>(<%=paramsString.toString()%>); > <% } >} // STATEMENTS > if (opx.getReturnRef() != null) { %> > return > <%=opx.getReturnRef().getName()%>; > <% } >} // EOPERATIONIMPL %>
#p#分页标题#e#
对 JET 的具体接头超出了本文的范畴。可是,因为 JET 模板对我们的操纵进程至关重要,我们将在伪代码方面回首一下模板的内容。请记着,在处理惩罚模板之前,第一个变量 genOperation 已经被 Ecore/JET 预初始化。
清单 4. genOperation 被 Ecore/JET 预初始化
Is this GenOperation is an EOperationImpl?
If false, emit default UnsupportedOperationException
STOP;
Else, cast it to EOperationImpl;
continue;
Find and declare all elements of type LocalVariable, initializing Java Objects to null;
Iterate through all Statements;
Emit Java code according to the subtype;
Does the implementation return something?
If yes, emit the return statement;
在构建详细模子之前,需要执行一些操纵。首先,在 templates/model/Class.javajet 顶部,我们必需将以下内容添加到导入列表(标志为粗体的前两行):
<%@
jet
package="org.eclipse.emf.codegen.ecore.templates.model"
imports="ecorex.* org.eclipse.emf.common.util.* \
java.util.* org.eclipse.emf.codegen.ecore.genmodel.*"…
虽然,EcoreX 包是颠末扩展的元模子。接下来,我们需要为我们的详细模子(My.ecore,范例为 ‘.ecorex’)建设和设置一个 EMF(GenModel)。为此,在模子上右键单击并选择 New > Other > Eclipse Modeling Framework > EMF Model(对付 EMF V2.5+ [Galileo, Helios],应选择 New > Other > Eclipse Modeling Framework > EMF Generator Model。)建设完成之后,需要在属性组 Templates & Merge 下设置 3 个属性,在 Model 下设置第四个属性。
图 16. GenModel — Templates & Merge
将 Dynamic Templates 配置为 true。
指定 Template Directory。
将 EMFX(扩展的元模子插件 ID)添加到 Template Plug-in Variables。
最近版本:在 Model 组属性下,将 Suppress Interfaces 配置为 true。
此刻可以举办构建了,右键单击 GenModel 并选择 Generate Model Code。假如一切顺利,在详细的 Test 项目(我们的项目称为 Test2)的源文件夹(src)中,您应该可以看到生成的 Java 源代码包和类,个中一个名为 mypackage.impl.MyClassImpl.java。打开该文件,您应该会看到两个生成的要领。
清单 5. MyClassImpl.java
public
void printTimestampMessage(String message) {
// created by implementedGenOperation.TODO.override.javajetinc
// ** EOperationX implementation **
java.lang.String timestampStr = null;
long timestamp;
timestampStr = "; Timestamp = ";
timestamp = java.lang.System.currentTimeMillis();
java.lang.System.out.print(message);
java.lang.System.out.print(timestampStr);
java.lang.System.out.println(timestamp);
}
public
int getDayOfWeek(int year, int month, int date) {
// created by implementedGenOperation.TODO.override.javajetinc
// ** EOperationX implementation **
int result;
int DAY;
java.util.Calendar calendar = null;
calendar = java.util.Calendar.getInstance();
calendar.set(year , month , date);
DAY = java.util.Calendar.DAY_OF_WEEK;
result = calendar.get(DAY);
return result;
}
可以添加一个 main 要领测试这个类。
告诫和妨碍诊断
Ecore 文件定名 (EMF V2.5+)
#p#分页标题#e#
在 EMF V2.5 之前,正如上面的几个屏幕快照所示,从一个扩展了的 Ecore 模子生成的详细模子应该保存 ‘.ecorex’ 的扩展名(如建设时的领导所发起的那样)。这有助于区别扩展了的模子与 ‘低级的’ Ecore 模子。然而,在 EMF 的最新版本中,genmodel 领导(如在图 16 之前所表明的)不接管除 .ecore 之外的其他文件扩展名。
JET Editor 范围性
要得到 JET 模板的语法突出显示成果,您需要安装 Eclipse JET Editor(JET Editor Plugin 最近已经从 EMF 迁移到 M2T)。
可是,在撰写本文时,JET Editor 的最新版本不能正确处理惩罚 Java 内容辅佐或嵌套 JET 包括文件(好比 .javajetinc 文件)的动态编译。另外,为了确保构建乐成,只能在父文件(好比上面的 Class.javajet)中指定导入操纵,而不能在包括的文件中指定。
实际上,利用一些特别设置(即,利用项目标上下文菜单),您可以将 EMF 动态模板项目(本文示例中的 Test2)转换为 JET 项目。在实践中,上面提及的范围性以及 EMF 和 M2T/JET 之间缺少集成,使得这种要领不太可行。
因此,很难捕捉和纠正包括的模板文件中的错误。由于在生成最终代码之前,JET 模板首先会被编译为一种中间 Java 文件(默认环境下位于一个埋没的 Java 项目 JETEmitter 中),所以通过从 Eclipse 的 Package Explorer 视图中删除过滤器,您可以或许看到这些编译错误。假如这只是模板文件中的名目错误,在构建期间将会呈现一个 Eclipse 弹出窗口。或者在将来的 JET 版本中,我们会看到更多的改造成果。
未举办模子验证
本文中的示例未利用 EMF Validation Framework 或 OCL 成果。所以,模子中的纷歧致性将会导致构建失败,譬喻,一个 EOperationImpl 可以声明某种返回范例,可是 Return Ref 属性可以引用差异的范例可能为空。在构建模子期间,将不会发明这些错误,并且生成的代码将无法编译。可以对元模子举办改造,利用 OCL 加强完整性和约束。
竣事语
我们看到了如何扩展 Ecore 元模子,将合成的 Java 要领中的编程式行为观念化。通过导入 Ecore 自己,我们扩展了一些 Ecore 模子元素 — 尤其是 EOperation。然后构建了元模子,并利用编辑器设计了一个详细的测试模子,包罗以 EOperationImpl 形式建模的两个 Java 要领。我们设置并构建了 JET 模板,用于为 EOperationImpl 生成代码。