EcoreFactory ecoreFactory = EcoreFactory.eINSTANCE;
EcorePackage ecorePackage = EcorePackage.eINSTANCE;
//创建一Company类
EClass companyClass = ecoreFactory.createEClass();
companyClass.setName("Company");
//创建公司名
EAttribute companyName = ecoreFactory.createEAttribute();
companyName.setName("name");
companyName.setEType(ecorePackage.getEString());
companyClass.getEStrUCturalFeatures().add(companyName);
//创建一Employee类
EClass employeeClass = ecoreFactory.createEClass();
employeeClass.setName("Employee");
//在Employee类上添加一个名字属性
EAttribute employeeName = ecoreFactory.createEAttribute();
employeeName.setName("name");
employeeName.setEType(ecorePackage.getEString());
employeeClass.getEStructuralFeatures().add(employeeName);
//创建一Department类
EClass departmentClass = ecoreFactory.createEClass();
departmentClass.setName("Department");
//添加department标志数字
EAttribute departmentNumber = ecoreFactory.createEAttribute();
departmentNumber.setName("number");
departmentNumber.setEType(ecorePackage.getEInt());
departmentClass.getEStructuralFeatures().add(departmentNumber);
//department类能够包含到一个或多个employee的参考
EReference departmentEmployees = ecoreFactory.createEReference();
departmentEmployees.setName("employees");
departmentEmployees.setEType(employeeClass);
//指定它可能是一个或多个employee
departmentEmployees.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
departmentEmployees.setContainment(true);
departmentClass.getEStructuralFeatures().add(departmentEmployees);
//company能够包含到一个或多个departments的参考
EReference companyDepartments = ecoreFactory.createEReference();
companyDepartments.setName("department");
companyDepartments.setEType(departmentClass);
companyDepartments.setUpperBound(ETypedElement.UNBOUNDED_MULTIPLICITY);
companyDepartments.setContainment(true);
companyClass.getEStructuralFeatures().add(companyDepartments);
//创建一个包-描述company
EPackage companyPackage = ecoreFactory.createEPackage();
companyPackage.setName("company");
companyPackage.setNsPRefix("company");
companyPackage.setNsURI("http:///com.example.company.ecore");
companyPackage.getEClassifiers().add(employeeClass);
companyPackage.getEClassifiers().add(departmentClass);
companyPackage.getEClassifiers().add(companyClass);
通过使用反射API,你能创建并且初始化一个你的模型的实例:
//得到company工厂
EFactory companyFactory = companyPackage.getEFactoryInstance();
//使用工厂来创建company类的实例并且
//设置company名字
EObject company = companyFactory.create(companyClass);
company.eSet(companyName, "MyCompany");
//创建一个employee类的实例
EObject employee = companyFactory.create(employeeClass);
//使用反射API初始化employee的名字
employee.eSet(employeeName, "John");
//创建一个department类的实例
EObject department = companyFactory.create(departmentClass);
department.eSet(departmentNumber, new Integer(123));
//添加"John"到department
((List)department.eGet(departmentEmployees)).add(employee);
//添加department到company
((List)company.eGet(companyDepartments)).add(department);
四、 数据的串行化和反串行化
为了串行化你的模型实例,你需要把一个你的实例模型的根对象放置到一个资源中。EMForg.eclipse.emf.ecore.resource.Resource接口描述了一个物理的存储位置(例如文件或URL)并且提供方法以串行化和装载数据。每一种资源都被存储在一个ResourceSet中-它代表了一个资源集合-这些资源被一起创建和加载并答应在它们当中进行参考引用。非凡地,一个ResourceSet负责跟踪哪些资源已被装载并且保证这个ResourceSet中的资源不会被重复装载。
因为EMF能够处理多重模型源,例如XML模式,所以指定使用哪些资源来实现(反)串行化你的数据也是很重要的。通常,当你调用ResourceSet.createResource(URI)方法时,它查询Resource.Factory.Registry来查找一个工厂-该工厂是为该URI而注册的并且使用它来创建一个适当的资源实现。因此,在你(反)串行化你的数据以前,请确保你已注册了适当的资源工厂实现。EMF提供若干Resource.Factory实现:
·对于XML数据,使用org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl。
·对于XMI数据,使用org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl。
·对于Ecore模型,使用org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl。
你的工具箱中有了这些EMF资源后,你就能使用下面的代码来串行化你的数据:
//创建资源集和资源
ResourceSet resourceSet = new ResourceSetImpl();
//注册XML资源工厂
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi",
new XMIResourceFactoryImpl());
Resource resource = resourceSet.createResource(URI.createFileURI("c:/temp/company.xmi"));
//添加根对象到资源
resource.getContents().add(company);
//串行化资源-你还能指定串行化
//选项,它定义在org.eclipse.emf.ecore.xmi.XMIResource中
resource.save(null);
company.xmi被串行化后的形式如下:
<?xml version="1.0" encoding="ASCII"?>
<company:Company xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
xmlns:company="http:///com.example.company.ecore" name="MyCompany">
<department number="123">
<employees name="John"/>
</department>
</company:Company>
在反串行化过程中,XML数据的命名空间URI被用于定位所需要的Ecore包(它用于描述你的实例文档的模型)。因此,在你尝试装载任何模型以前,请确保你已经为你的文档将要使用的每个Ecore包注册了命名空间URI:
//在本地资源注册表中注册包
resourceSet.getPackageRegistry().put(companyPackage.getNsURI(), companyPackage);
//加载资源
resource.load(null);
注重到局部的和全局的包(EPackage.Registry.INSTANCE)以及资源工厂(Resource.Factory.Registry.INSTANCE)的注册差别也是很重要的。全局注册是静态的,因此任何应用程序在JVM生存期都能存取全局注册并且可能覆盖它。为确保你的注册不会覆盖全局注册并且反过来也如此,典型地,你最好使用局部资源集合注册。
五、 由XML模式生成动态的Ecore
如前所提及,假如你的模型是一个XML模式但是你没有选择生成Java类,那么,你可以通过使用XSDEcoreBuilder来动态地创建一个Ecore模型。这个示例使用了ipo.xsd:
XSDEcoreBuilder xsdEcoreBuilder = new XSDEcoreBuilder();
ResourceSet resourceSet = new ResourceSetImpl();
Collection eCorePackages =xsdEcoreBuilder.generate(URI.createFileURI("c:/temp/ipo.xsd"));
这个generate方法返回为这个模式中的每个URI生成的Ecore包。假如该模式导入了其它命名空间,那么将有多个Ecore包被返回。每个包是被注册到本地的资源集中-用于实现模式转换。因此,假如你使用同样的资源集来装载你的实例XML文档的话,你就不需要自己注册包。
因为XML模式包括更多概念而不仅仅是Ecore,例如通配符等,所以EMF使用Ecore EAnnotations来记录到XML模式的映射。在数据(反)串行化期间,EMF需要处理这些注解。为了确保这些注解在(反)串行化期间被加以考虑,你必须使用XMLResource.ExtendedMetaData选项:
HashMap options = new HashMap();
options.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE);
//请参考http://www.w3.org/TR/2004/PER-xmlschema-0-20040318/#ipo.xml
Resource resource = resourceSet.createResource(URI.createFileURI("c:/temp/ipo.xml"));
resource.load(options);
EMF 2.1还增加了一项新功能-它答应你在加载一个包含一个xsi:schemaLocation或xsi:noNamespaceSchemaLocation属性的XML文档时,不断地把模式转换成Ecore。同时,它也答应你加载一个没有与之相关联的模式的XML文档。为了使用这一功能,你需要注册 org.eclipse.emf.ecore.xmi.impl.GenericXMLResourceFactoryImpl:
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xml",new GenericXMLResourceFactoryImpl());
六、 小结
本文向你简短介绍了EMF,并解释了几个核心的EMF概念。同时,对于如何利用模式EMF的动态能力提供了相关示例。
新闻热点
疑难解答