在前几天的“折腾了一把JAX-WS, SOA & Java EE 5”中(http://www.javaresearch.org/article/116761.htm),

提到利用JAXB绑定的技术,将包含业务逻辑的Schema绑定,自动生成Java源代码。文中提到,生成的Java类最好能在

网络通讯中生存,即implements Serializable。另外,最好能在生成过程中,使生成类型继承共同的Super类,以便

于OOP技术的应用,如多态等。这样,我们不用手工修改绑定生成的代码。

上述目标可以通过对JAXB绑定的用户化(Jaxb Binding Customization)来实现。

一般的做法是定义一个JAXB绑定的用户化文件,并在我们的Schema文件中去引用就可以了。例如:

GlobalBindings.xsd

{code}

xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"

xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"

elementFormDefault="qualified"

jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.0">

{code}

应注意的一点是,Schema的引用有两个标签,即和,前者要求被引用的xsd与引用者要有

相同的namespace;否则,就要使用import。如果所有的生成类型都将继承 Service,那只要在Service.xsd中将上

述GlobalBindings.xsd引用就可以了。在Schema中可用标签来定义这种继承关系。

折腾来折腾去,发现一个JAXB不尽人意的地方,就是xjc在将xsd绑定位Java源代码时,当根据xsd的目录结构,将生

成的源代码也放置在相应的的目录底下时,xjc将在每个目录下重复产生被引用的Schema的类型。为了避免这种情况,

你只好将所有的Schema放置到同一目录下,而产生的源代码业将在同一目录下。这可太讨厌了,对于一定规模的SOA

应用来说,所有生成的请求及相应类都放在同一目录下是很难被接受的。

本文觉得有两个办法来实现生成的源代码分目录存放。一个是在绑定后,对源代码进行处理,反正是文本文件;另一个

办法就是在编制Schema时就对此进行考虑。本文将着重讨论后者,希望对读者有些启发。

Jaxb在对Schema进行绑定时,xjc提供了包参数选项,如果该参数没有输入,xjc将利用Schema中定义的namespace自

动产生包名(package name)。如果你的“targetNamespace="http://service.t50/portable/svice”,

生成的包名将是:“t50.service.portable.svice”。

这样,我们就可以利用xjc的这一缺省特点,根据Schema的目录结构,通过定义所需的namespace,来定义绑定后的源

代码的目录结构(也就是包名package name)。

假设我们的Schema目录结构是这样的:

“xsd/GlobalBindings.xsd”

“xsd/t50/Service.xsd”-- with namespace: "http://service.t50/portable"

“xsd/t50/ServiceCaller.xsd”-- with namespace: "http://service.t50/portable"

“xsd/t50/common/Person.xsd”-- with namespace: "http://service.t50/portable/common"

“xsd/t50/service/GetPerson.xsd”-- with namespace: "http://service.t50/portable/service"

通过xjc编译后,生成的Java包类则有:

“t50.service.portable”:ServiceRequest;ServiceResponse;ServiceCaller

“t50.service.portable.common”:Person

“t50.service.portable.service”:GetPersonRequest, GetPersonResponse

这样,就基本上实现了绑定生成的类型的分目录存放目的了。本文基本上给出了一个通过JAXB绑定来实现一个SOA项目的

框架结构。Schema的定义是其中的关键部分,而本文的Schema定义原型已基本上初具规模,可以作为一个项目的开始。

总体感觉是,Jaxb技术已经成熟,但尚有很多可完善之处,尤其是xjc编译输出的灵活性等,有待优化提高。

如果你有好的建议,或本文有错谬之处,希望指出,大家一起提高。

以下是相关的Schema及相应的源代码:

Service.xsd

{code}

xmlns:sc="http://service.t50/portable"

targetNamespace="http://service.t50/portable"

xmlns:xs="http://www.w3.org/2001/XMLSchema"

elementFormDefault="qualified" attributeFormDefault="unqualified">

{code}

GetPerson.xsd

{code}

xmlns:xs="http://www.w3.org/2001/XMLSchema"

xmlns:bc="http://service.t50/portable"

xmlns:cm="http://service.t50/portable/common"

xmlns:sc="http://service.t50/portable/service"

targetNamespace="http://service.t50/portable/service"

elementFormDefault="qualified"

attributeFormDefault="unqualified">

schemaLocation="../Service.xsd"/>

schemaLocation="../common/Person.xsd"/>

Service request type

Service response type

{code}

t50.service.portable.serivce.GetPersonRequest.java (comments removed)

{code}

package t50.service.portable.service;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlAccessType;

import javax.xml.bind.annotation.XmlAccessorType;

import javax.xml.bind.annotation.XmlElement;

import javax.xml.bind.annotation.XmlRootElement;

import javax.xml.bind.annotation.XmlType;

import t50.service.portable.ServiceRequest;

@XmlAccessorType(XmlAccessType.FIELD)

@XmlType(name = "", propOrder = {

"personId"

})

@XmlRootElement(name = "getPersonRequest")

public class GetPersonRequest

extends ServiceRequest

implements Serializable

{

private final static long serialVersionUID = 1L;

@XmlElement(namespace = "http://service.t50/portable/service")

protected int personId;

public int getPersonId() {

return personId;

}

public void setPersonId(int value) {

this.personId = value;

}

}

{code}

SOAP request payload: GetPersonRequest.xml

{code}

xmlns:fn="http://www.w3.org/2005/xpath-functions"

xmlns:xs="http://www.w3.org/2001/XMLSchema">

xmlns:sc1="http://service.t50/portable"

xmlns:sc2="http://service.t50/portable/common"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://service.t50/portable/service GetPerson.xsd ">

john

password

2008

{code}