看到eclipse3.2里面的GMF, 觉得比较有趣,底层还是用到了EMF. 花了两天时间仔细研究了以下EMF,的确是个好东西.

EMF根据ecore建模(可以和schema的xsd相互转换)生成强类型的EMF代码. 这个强类型更强的地方是可以取得meta信息,从而可以用于校验和界面辅助信息的生成.类似于动态bean,属性也可以根据名称动态取得.

以前考虑过用xsd描述界面, 但是数据载体只能是xml, 即使利用apache的schema编译工具生成强类型的类,后台代码也是xml. 不利于持久化. emf在代码生成引擎比较智能,可以标记出用户代码和自动生成代码.不会有生成覆盖问题.

这里做个简单示例:
1. Ecore:
可以新建Ecore, 建立好以后用GMF可视化编辑(Eclipse3.2RC2)

2. 生成Model:
点击my.ecore文件,菜单:File->New->Other->Eclipse Modeling Framework->EMF Model
3. 打开生成的my.genmodel, 选择树顶点的:Generate Model Code
生成的代码里面会有一个编译错误. 是中文编程的问题, 中文没有大小写(先天不足啊),结果性别这个成员变量和性别类名混淆,出错.在错误代码前面加上包全名即可.
4. 利用生成的代码构建一个家庭,输出xml并且校验之:

import  java.io.IOException;
import  java.util.Iterator;

import  org.eclipse.emf.common.util.Diagnostic;
import  org.eclipse.emf.common.util.URI;
import  org.eclipse.emf.ecore.EObject;
import  org.eclipse.emf.ecore.resource.Resource;
import  org.eclipse.emf.ecore.util.Diagnostician;
import  org.eclipse.emf.ecore.xmi.XMLResource;
import  org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl;
import  org.steeven.family.FamilyFactory;
import  org.steeven.family.人物;
import  org.steeven.family.家庭;
import  org.steeven.family.性别;

public   class  TestMy  {

    
public   static   void  main(String[] args)  throws  IOException  {
        testFamily();
    }


    
private   static   void  testFamily()  throws  IOException  {
        家庭 family 
=  FamilyFactory.eINSTANCE.create家庭();
        family.setTitle(
" steeven家 " );
        family.set老公(FamilyFactory.eINSTANCE.create人物());
        family.get老公().set姓名(
" steeven " );
        family.set老婆(FamilyFactory.eINSTANCE.create人物());
        family.get老婆().set姓名(
" stella " );
        family.get老婆().set性别(性别.女_LITERAL);
        人物 sophie 
=  FamilyFactory.eINSTANCE.create人物();
        sophie.set姓名(
" sophie " );
        sophie.set性别(性别.女_LITERAL);
        family.get兔崽子().add(sophie);
        dump(family);
        validate(family);
    }


    
private   static   void  validate(EObject family)  {
        Diagnostic diagnostic 
=  Diagnostician.INSTANCE.validate(family);
        System.out.println(diagnostic);
        
for  (Iterator it  =  diagnostic.getChildren().iterator(); it.hasNext();)  {
            Diagnostic diag 
=  (Diagnostic) it.next();
            System.out.println(diag.getMessage());
        }

    }


    
private   static  Resource dump(EObject objs)  throws  IOException  {
        
//  ResourceSet rs = new ResourceSetImpl();
        
//  rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put(
        
//  Resource.Factory.Registry.DEFAULT_EXTENSION,
        
//  new XMIResourceFactoryImpl());
        
//  Resource resource = rs.createResource(URI
        
//  .createFileURI("c:\\temp\\test.xml"));
        XMLResource resource  =   new  XMLResourceImpl(URI
                .createFileURI(
" c:\\temp\\test.xml " ));
        resource.setEncoding(
" GBK " );
        
for  (EObject obj : objs)
            resource.getContents().add(obj); 
//  目前版本不加入resource验证会报singling异常
        resource.save(System.out,  null );
        
return  resource;
    }

}

运行结果如下:

<? xml version="1.0" encoding="GBK" ?>
< family: 家庭 xmlns:family ="http://org.steeven/family"  title ="steeven家"  老公 ="/"  老婆 ="/"  兔崽子 ="/" />
Diagnostic ERROR 
The feature '老公' of 'org.steeven.family.impl.家庭Impl@f6a746{file:/c:/temp/test.xml#/}' contains a dangling reference 'org.steeven.family.impl.人物Impl@6eb38a{#//}'
The feature '老婆' of 'org.steeven.family.impl.家庭Impl@f6a746{file:/c:/temp/test.xml#/}' contains a dangling reference 'org.steeven.family.impl.人物Impl@1cd2e5f{#//}'
The feature '兔崽子' of 'org.steeven.family.impl.家庭Impl@f6a746{file:/c:/temp/test.xml#/}' contains a dangling reference 'org.steeven.family.impl.人物Impl@19f953d{#//}'

可见输出的xml中没有包含人物的具体信息. 修改my.ecore中老公/老婆/兔崽子属性的containment属性为true,重新生成代码后运行结果如下:
<?xml version="1.0" encoding="GBK"?>
<family:家庭 xmlns:family="http://org.steeven/family" title="steeven家">
  
<老公 姓名="steeven"/>
  
<老婆 性别="女" 姓名="stella"/>
  
<兔崽子 性别="女" 姓名="sophie"/>
</family:家庭>
Diagnostic OK


====================
EMF单独运行成功~

这里ECORE似乎不支持嵌套定义,不像schema那样一个complexType声明里面可以定义的很复杂, 也不像Java的内部类. 似乎被作了简化, 更像关系数据库表之间的关系.

待求证问题:
1. EMF的校验信息是否支持国际化.
2. EMF数据的能否更方便的保存到数据.

EMF的灵活和强大已经验证过, 用于C/S还是B/S应该都不是问题.