Jhonse技术 2010-03-12
1. 项目简介
Castor是一个开源的Java项目。其主要目标是在XML数据、Java对象和数据库关系数据之间提供一种直接的映射,使得这三种对象数据可以相互之间自由转换。Castor项目在2000年3月发布第一个0.8版本,项目几经重构设计目前最新版本为1.1.2.1。
Castor项目主要包括XML与Java对象的映射(CastorXML),Java对象与关系数据库表映射(CastorJDO)两个关键功能。在Castor中,我们通过定义数据映射(Mapping)文件,在XML文档元素(节点、属性、文本等),Java类(类、字段属性等)和数据库表(关联表、表、字段)之间建立一一映射。通过XMLSchema定义可以自动生成实体Java类定义,通过实体Java类定义可以自动生成XML元素与Java类之间的映射文件。
目前,优秀的Java对象关系映射(O/RMapping)框架已经很多,商业化的如Oracle的TopLink,开源的如Hibernate,iBatis,Cayenne等,这些O/R框架的实现各有特点。Sun针对对象关系映射提出了JDO规范,针对XML与Java对象之间的绑定提出了JAXB规范。Castor的优势在于其提供O/R映射功能的同时提供了XML与Java对象间数据映射功能,通过使用集成的映射定义文件,XML数据,Java对象和关系数据之间可以无缝的相互转换。
2.Castor功能特性
1.CastorXML在Java对象模型与XMLInfoSet之间建立相互转换和数据绑定功能;
2.提供从XML文档定义自动是生成Java类定义文件的功能(CodeGenerator);
3.通过自省方式在XML文档与Java对象间建立映射(不需要提供XMLSchema和XMLMapping文件);
4.通过定义映射文件在XML文档实体与Java对象实体间建立映射;
5.CastorJDO为Java对象与数据库关系数据之间提供一种序列化与反序列化的框架。CastorJDO不同于Sun公司提出的JDO概念,但两者具有相似的目标;
6.CastorJDO以映射文件的方式定义Java对象模型与关系数据库表模型之间的映射;
7.基于XML映射文件的方式定义三种不同数据对象模型之间的映射;
8.提供内存缓存和提交写入(writeatcommit)方式,减少数据库JDBC操作;
9.支持两阶段事务,对象操作回滚和数据库锁定侦测;
10.支持OQL与标准SQL之间的映射,CastorJDO对象查询采用OQL语言;
11.提供基于Java实体对象类定义生成映射文件的功能;
12.提供基于XML输入文档生成Schema定义文件的功能;
我们将在下述章节中详细介绍Castor的上述功能,并给出操作示例。
3.CastorXML
CastorXML作为一个数据绑定框架,可以实现任何类似JavaBean的对象和XML文档表示之间的相互转换。通常情况下,Castor使用一组类描述符(ClassDescriptor)和字段描述符(FieldDescriptor)集来定义一个Java对象如何编组(Marshall)成XML数据或者从XML数据解编(Unmarshall)为Java对象。
3.1XML编组(Marshalling)框架
XML编组框架实现Java对象与XML文档间的相互转换。在下文中,除非显式提及,否则编组框架指编组和解编两种功能。Castor XML编组框架包含在两个主要的类org.exolab.castor.xml.Marshaller和org.exolab.castor.xml.Unmarshaller中。Castor XML编组解编功能示意如下图所示:3.1.1 自省方式(introspection)的编组与解编下面我们通过一个简单的示例展示XML编组框架以自省的方式在Java对象与XML文档之间转换的功能。首先,定义一个简单的Person类,该类包含两个字段:name和 birthday,分别指定义某个人的名字和出生日期。Person类定义如下:
import java.util.Date;
/**Ansimplepersonclass*/
publicclassPersonimplementsjava.io.Serializable{
/**Thenameoftheperson*/
privateStringname=null;
span>/**TheDateofbirth*/
privateDatebirthday=null;
/**CreatesaPersonwithnoname*/
publicPerson(){
super();
}
/**CreatesaPersonwiththegivenname*/
publicPerson(Stringname){
this.name=name;
}
/**
*@returndateofbirthoftheperson
*/
publicDategetDateOfBirth(){
returnbirthday;
}
/**
*@returnnameoftheperson
*/
publicStringgetName(){
returnname;
}
/**
*Setsthedateofbirthoftheperson
*@paramnamethenameoftheperson
*/
publicvoid setDateOfBirth(Date http://msnpiki.msnfanatic.com/index.php/Main_Page-->#0000c0">birthday) {
this.birthday=birthday;
}
/**
*Setsthenameoftheperson
*@paramnamethenameoftheperson
*/
publicvoidsetName(Stringname){
this.name=name;
}
}然后,我们定义一个Person类的实例并将其编组输出为XML,示例代码如下:
// 创建一个新的Person对象
Personperson=newPerson("Ryan'MadDog'Madden");
Calendarbirthday=newGregorianCalendar(1955,8,15);
person.setDateOfBirth(birthday.getTime());
//构建编组后的XML文档输出
FileWriterwriter=newFileWriter("d:\\test.xml");
//编组Person实例为XML文档
Marshaller.marshal(person,writer);
上述代码输出结果为:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<name>http://msnpiki.msnfanatic.com/index.php/Main_Page-->
te; COLOR: black">Ryan 'Mad Dog' Madden</name>
<date-of-birth>3855-09-15T00:00:00.000+08:00</date-of-birth>
</person>下面的代码读取上述输出的XML文档并将解编为Java对象:
// 构建输入XML文档的Reader
FileReaderreader=newFileReader("d:\\test.xml");
//解编XML文档为Person对象
person=(Person)Unmarshaller.unmarshal(Person.class,reader);
System.out.println("name="+person.getName());
输出结果为:
Name=Ryan'MadDog'Madden
3.1.2使用映射文件方式的编组与解编
调用Marshaller和Unmarshaller的实例方法时,必须提供XML文档结构和Java类模型间的映射定义文件。关于Mapping映射文件的定义我们会在下述章节中给出详细介绍。下面是调用Marshaller和Unmarshaller的实例方法的代码示例:// 加载映射文件
Mappingmapping=newMapping();
mapping.loadMapping("mapping.xml");
//为待解编的XML文档构建一个Reader
reader=newFileReader("test.xml");
//http://msnpiki.msnfanatic.com/index.php/Main_Page-->
">构建一个解编器Unmarshaller
Unmarshallerunmarshaller=newUnmarshaller(Person.class);
unmarshaller.setMapping(mapping);
//解编XML文档为Person对象
Person person = (Person) unmarshaller.unmarshal(reader);
3.1.3小结
上述示例展示了使用Marshaller和Unmarshaller类的静态方法以自省的方式实现XML文档与Java对象之间的编组和解编,以及使用Mapping映射文件通过调用Marshaller和Unmarshaller的实例方法实现XML文档与Java对象之间的编组和解编两种方式。
前一种方式不需要构造Marshaller和Unmarshaller的实例;后一种方式需要构造Marshaller和Unmarshaller的实例,调用非静态方法完成上述功能。调用Marshaller和Unmarshaller的实例方法时,必须提供XML文档结构和Java类模型间的映射定义文件。
注意:当使用Marshaller和Unmarshaller的静态方法时,即使指定了映射定义文件,此映射定义也会被忽略。
3.2CastorXML的编组/解编机制
Castor通过类描述符和字段描述符几乎可以编组/解编所有的Java对象。当某个Java对象类描述符不存在时,编组框架通过使用反射(Reflection)方式获取对象的结构信息,并在内存中为此对象构造类描述符和字段描述符。当实体类的描述符存在时,Castor使用这些描述符提供的Java对象模型信息用来处理编组和解编。
编组与解编过程中,Castor要求实体类定义必须提供”public”类型的默认构造函数(不含参数)声明以及必要的”getter”和”setter”方法。
3.2.1类描述符
类描述符(org.exolab.castor.xml.XMLClassDescriptor)使得编组框架具有足够的信息以正确的处理编组/解编过程。在Castor中,类描述符由XML编组框架和JDO框架(后文详细描述)共享。每个类描述符包含一组字段描述符(org.exolab.castor.xml.XMLFieldDescriptor)。
XML类描述符具有两种构建方式:编译时构建和运行时构建。
l编译时构建描述符
在编译时构建类描述符,一种方法是为每一个需要编组的实体类实现org.exolab.castor.xml.XMLClassDescriptor接口;另一种方式是使用Castor提供的源代码生成器通过XMLSchema定义文档在生成Java实体类定义的同时,为Java实体类生成相应的类描述符。
编译时构建类描述符的方式的主要优点是其执行速度快于运行时构建方式。
l运行时构建描述符
使用运行时构建类描述符时,Castor可以直接通过反射自省方式Java实体类,也可以提供映射定义文件。这两种方式可以结合使用。对于默认的自省方式,实体类必须为必要的字段提供适当的setter/getter方法;如果没有给编组的字段数据指定setter/getter方法,Castor只能访问类型为”public”的字段。如果上述条件都不满足,Castor将不处理上述字段。
在Castor中,自省方式默认启动,不需要做任何设置。用户可以在castor.properties文件中设定必要的参数来控制自省方式的行为,如字段命名惯例,原始类型默认看作XML属性还是节点(Element)。用户可以查看castor.properties文件(在Castor发布Jar包中的”org/exolab/castor”路径下)获取详细信息。
使用映射文件描述实体类时,用户需要在编组/解编操作前加载映射定义。映射定义参考(org.exolab.castor.mapping.Mapping)。
3.3使用XMLContext获取编组器和解编器
Castor自 V1.1.2版本开始在XML编组框架中提供了XMLContext类,用于方便高效的获取Marshaller和Unmarshaller实例。上述3.1节中编组解编Person类实例的例子使用XMLContext实现的方式如下:import org.exolab.castor.xml.XMLContext;
importorg.exolab.castor.mapping.Mapping;
importorg.exolab.castor.xml.Unmarshaller;
//构建Mapping实例
Mappingmapping=XMLContext.createMapping();
mapping.loadMapping("mapping.xml");
//构建一个XMLContext实例并设定映射
XMLContextcontext=newXMLContext();
context.addMapping(mapping);
//构建一个Unmarshaller
Unmarshallerunmarshaller=context.createUnmarshaller();
unmarshaller.setClass(Person.class);
//为待解编的XML文档构建一个
n>Reader
Readerreader=newFileReader("test.xml");
// 从XML文档中解编person对象Person person = (Person) unmarshaller.unmarshal(reader);
如上述代码所示,XMLContext提供了不同的工厂方法用于获取新的Marshaller,Unmarshaller和Mapping实例。当在一个应用中需要使用不止一个Unmarshaller实例时,可以根据需要调用XMLContext的createUnmarshaller实例方法。从同一个XMLContext实例获取多个Unmarshaller实例时开销很小。需要注意的是,Unmarshaller不是线程安全的。