Axis
是
Java
陣營(yíng)中最常用的一個(gè)
Web
服務(wù)組件。通過一些配置就可以利用它去生成、部署
Web
服務(wù)。
但是目前
Axis
只支持
XMLBean
、
Castor
和
JavaBean
復(fù)雜類型數(shù)據(jù)結(jié)構(gòu),于是在使用的時(shí)候,特別是一些比較高級(jí)的
Web
服務(wù)使用的時(shí)候,復(fù)雜數(shù)據(jù)類型就會(huì)受到一定的限制。這里我給出一個(gè)關(guān)于如何讓
Axis
支持
EMF
模型的例子,希望能借此能給讀者一些提示。在這里我假設(shè)讀者都使用過
Axis
,如果需要獲得更多的
Axis
信息,請(qǐng)點(diǎn)這里。關(guān)于EMF的信息可以從這里獲得。相關(guān)代碼下載
1.??????
類型映射
在
Axis
的
Server-config.wsdd
文件中,我們需要自己定義部署的服務(wù)的一些配置信息,其中有一個(gè)名為
typeMapping
的元素,該元素就是配置如何映射復(fù)雜類型數(shù)據(jù)結(jié)構(gòu)的一些信息。
typeMapping
元素具有以下屬性:
1)?
Deserializer?
反序列化
XML
到我們所需要對(duì)象的
DeserializerFactory
類
???2)? Serializer???? 序列化對(duì)象到 XML 的 SerializerFactory 類
???3)? encodingStyle? 編碼類型,我一般設(shè)為空
???4)? type??????????? 需要映射的復(fù)雜類型數(shù)據(jù)對(duì)象類
???5)? qname?????????? 數(shù)據(jù)類型在 XML 中對(duì)應(yīng)的 QName (命名空間加上元素的名稱)
當(dāng)我們?cè)L問某個(gè)
Web
服務(wù)時(shí),如果返回類型,或者是我們的客戶端調(diào)用代碼中涉及到了復(fù)雜類型,
Axis
會(huì)去查詢我們
typeMapping
中定義好的并且和該復(fù)雜類型匹配的
DeserializerFactory
或者
SerializerFactory
類,然后返回對(duì)應(yīng)的
Deserializer
和
Serializer
類,通過該類序列化或者反序列化這個(gè)復(fù)雜類型。所以如果我們所定義的復(fù)雜類型并非
Castor
、
JavaBean
、
XMLBean
的時(shí)候,就需要我們自己去創(chuàng)建
DeserializerFactory
和
SerializerFactory
。
2
.
DeserializerFactory
和
Deserializer
反序列化工廠是用戶將 XML 轉(zhuǎn)成 Java 對(duì)象的工廠,它維護(hù)了一個(gè) Deserializer 對(duì)象,該對(duì)象才是真正去做反序列化工作的類。
我們現(xiàn)在創(chuàng)建自己的
Deserializer
類以及
Deserializer
工廠類:
?? public ?EMFDeserializerFactory?(Class?javaType,?QName?xmlType)?{
????????? super (javaType,?xmlType);
?????????deserClass? =??EMFDeserializer.class ;
??}
? public ?Deserializer?getDeserializerAs(String?mechanismType)? throws ?JAXRPCException?{
????????? return ? new ?EMFDeserializer(javaType,xmlType);
?}
}
工廠類的實(shí)現(xiàn)比較簡(jiǎn)單,我們先繼承 BeanDeserializerFactory 類,然后復(fù)寫它的 getDeserializerAs 方法,返回相應(yīng)的 Deserializer 類即可。
??????? private ?Object?sdoValue? = ? null ;
??????? private ?Class?valueVlazz? = ? null ;
??????? public ?EMFDeserializer(Class?arg0,?QName?arg1)?{
??????????????valueVlazz? = ?arg0;
???????}
??????? public ? void ?onEndElement(String?namespace,?String?localName,
?????????????????????DeserializationContext?context)? throws ?SAXException?{
???????????

???????}
?}
EMFDeserialize
的工作就是將
XML
文檔轉(zhuǎn)成
EMF
模型。
我們繼承
DeserializeImpl
類,然后復(fù)寫它的
onEndElement
方法。
??????? public ? void ?onEndElement(String?namespace,?String?localName,
?????????????????????DeserializationContext?context)? throws ?SAXException?{
??????????????…….
}
}
在
onEndElement
方法中的參數(shù)有一個(gè)
DeserializationContext
對(duì)象,我們可以通過它獲得
XML
文檔片段:
該
Document
就是得到的
XML
片段。
然后我們通過
EMF
提供的
Resource
對(duì)象將
XML
文檔進(jìn)行反序列化(這里我自己寫了一個(gè)創(chuàng)建
XMLResourceImpl
的工廠類,讀者可以在文章后面下載代碼):
???? new ?org.apache.xml.serialize.DOMSerializerImpl();
String?ddd? = ?s1.writeToString(doc);
Resource?resource? = ?GenaralEObjectXMLResourceFactory.getInstance()
???????????????????????????????????.createResource( null );
resource.load( new ?ByteArrayInputStream(ddd.getBytes()),
???????????????????????????????????Collections.EMPTY_MAP);
先將
Document
轉(zhuǎn)成
String
,然后通過
ByteArrayInputStream
傳給
resource,resource
在
load
后會(huì)生成對(duì)應(yīng)的數(shù)據(jù)對(duì)象,并且我們可以通過
resource
獲得:
value? = ?sdoValue;
這里需要注意的是,如果我們生成的
EMF
模型是通過
XSD
來(lái)生成的,那反序列化后得到的應(yīng)該是一個(gè)
DocumentRoot
對(duì)象,該對(duì)象可能并不是我們想得到的,比如:
< student? name =”me”/>
得到的對(duì)象并是不
Student
對(duì)象,而是一個(gè)
DocumentRoot
,而
Student
對(duì)象是包含在
DocuementRoot
對(duì)象的子對(duì)象中。
但是如果是直接通過
Ecore
模型生成的則不會(huì)有
DocumentRoot
對(duì)象。這里如何去判斷得到的對(duì)象是不是
DocumentRoot
需要讀者進(jìn)一步去看看
EMF
,這里我沒有給出通用的手段解決,只是根據(jù)我本身程序的需求去獲得的:
????List?contents? = ?((EObject)sdoValue).eContents();
?? ? for ?(Iterator?iter? = ?contents.iterator();?iter??.hasNext();)?{
?????????????Object?element? = ?(Object)?iter.next();
??????????? if (valueVlazz.isInstance(element)){
??????????????????????value? = ?element;
?????????????????????? break ;
????????????}
????}
?}
這里需要注意,對(duì)象
value
并不是
EMFDeserializer
自己定義的字段,而是
DeserializerImpl
的字段,該字段就是
Axis
反序列化后的對(duì)象值引用字段。
3.???
Serializer
和
SerializerFactory
SerializerFactory
的工作和
DeserializerFactory
工作類似,返回一個(gè)
Serializer
對(duì)象,它是真正去將對(duì)象序列化成
XML
的類。
SerializerFactory
比較簡(jiǎn)單,這里就不詳細(xì)介紹了:
????????? public ?EMFSerializerFactory(Class?javaType,?QName?xmlType)?{
??????????????? super (EMFSerializer. class ,?xmlType,?javaType);
???????}
}
Serializer
類需要繼承
Serializer
接口:
??????? protected ?Class?javaType;
???????? protected ?QName?xmlType;
???????? public ?SDOSerializer(Class?javaType,?QName?xmlType)?{
?????????????? this .javaType? = ?javaType;
?????????????? this .xmlType? = ?xmlType;
???????}
??????? public ? void ?serialize(QName?name,?Attributes?attributes,?Object?value,
?????????????????????SerializationContext?context)? throws ?IOException?{
???????????

???????}???????
??????? public ?Element?writeSchema(Class?javaType,?Types?types)? throws ?Exception?{
????????????? return ? null ;
???????}
??????? public ?String?getMechanismType()?{
?????????????? return ?Constants.AXIS_SAX;
???????}
}
我們需要實(shí)現(xiàn)三個(gè)方法:
1)?
serialize
???2)? getMechanismType
???3)?
writeSchema
writeSchema
方法需要返回一個(gè)
XML Schema
的
Element
對(duì)象,該
XML Schema
是指我們所用的
EMF
模型對(duì)應(yīng)的
XML Schema
,我采用的
EcoreXMLSchemaBuilder
類就可以將
EPackage
對(duì)象轉(zhuǎn)換成為一個(gè)
Schema Element
。不過在這里我發(fā)現(xiàn)好像
Axis
對(duì)這個(gè)方法并不是說(shuō)非用不可,我也就沒有實(shí)現(xiàn),直接返回的是
NULL
getMechanismType
方法很簡(jiǎn)單
??? return ?Constants.AXIS_SAX;
}
這樣就可以了
最重要的是 serialize 方法,這個(gè)方法就是將對(duì)象進(jìn)行序列化的方法:
?????????????????????SerializationContext?context)? throws ?IOException?{
??????????????…..
}
首先要將傳入的 value 序列化成一個(gè) XML 文檔:
?????????????????????String?targetURI? = ?ePackage.getNsURI();
?????????????????????Registry.INSTANCE.put(targetURI,ePackage);
?????????????????????Resource?resource? = ?GenaralEObjectXMLResourceFactory.getInstance().createResource( null );
?????????????????????resource.getContents().add(value);
?????????????????????ByteArrayOutputStream?stream? = ? new ?ByteArrayOutputStream();
?????????????????????resource.save(stream,?Collections.EMPTY_MAP);
我們將序列化后的
XML
存放到了
stream
流中,現(xiàn)在我們需要將這段
XML
寫到
SerializationContext
對(duì)象中:
?context.startElement(name,attributes);
??DOMParser?parser? = ? new ?DOMParser();
InputSource?inputSource? = ? new ?InputSource();
??inputSource.setByteStream( new ?ByteArrayInputStream(stream.toByteArray()));
??parser.parse(inputSource);
??context.writeDOMElement(parser.getDocument().getDocumentElement());
?????????????????????????????????????????????????????context.endElement();
這樣我們就完成了對(duì)對(duì)象的序列化。
4.
修改
wsdd
文件
當(dāng)我們使用
Axis
提供的
WSDL2Java
工具類時(shí),
Axis
會(huì)自動(dòng)給我們生成一個(gè)
wsdd
文件,而且當(dāng)它發(fā)現(xiàn)定義的
Operation
中涉及到了復(fù)雜類型數(shù)據(jù),
Axis
會(huì)自動(dòng)加上
typeMapping
元素,但是它默認(rèn)給這個(gè)元素上定義的
Deserializer , Serializer
是針對(duì)
JavaBean
的,所以如果我們的類是是
EMF
,只要將
typeMapping
的類型改成
EMFSerializerFactory
以及
EMFDeserializerFactory
就可以了。
5.
總結(jié)
上面是小弟的一點(diǎn)愚見,請(qǐng)各位看官多提意見