Axis
是
Java
陣營中最常用的一個
Web
服務組件。通過一些配置就可以利用它去生成、部署
Web
服務。
但是目前
Axis
只支持
XMLBean
、
Castor
和
JavaBean
復雜類型數據結構,于是在使用的時候,特別是一些比較高級的
Web
服務使用的時候,復雜數據類型就會受到一定的限制。這里我給出一個關于如何讓
Axis
支持
EMF
模型的例子,希望能借此能給讀者一些提示。在這里我假設讀者都使用過
Axis
,如果需要獲得更多的
Axis
信息,請點這里。關于EMF的信息可以從這里獲得。相關代碼下載
1.??????
類型映射
在
Axis
的
Server-config.wsdd
文件中,我們需要自己定義部署的服務的一些配置信息,其中有一個名為
typeMapping
的元素,該元素就是配置如何映射復雜類型數據結構的一些信息。
typeMapping
元素具有以下屬性:
1)?
Deserializer?
反序列化
XML
到我們所需要對象的
DeserializerFactory
類
???2)? Serializer???? 序列化對象到 XML 的 SerializerFactory 類
???3)? encodingStyle? 編碼類型,我一般設為空
???4)? type??????????? 需要映射的復雜類型數據對象類
???5)? qname?????????? 數據類型在 XML 中對應的 QName (命名空間加上元素的名稱)
當我們訪問某個
Web
服務時,如果返回類型,或者是我們的客戶端調用代碼中涉及到了復雜類型,
Axis
會去查詢我們
typeMapping
中定義好的并且和該復雜類型匹配的
DeserializerFactory
或者
SerializerFactory
類,然后返回對應的
Deserializer
和
Serializer
類,通過該類序列化或者反序列化這個復雜類型。所以如果我們所定義的復雜類型并非
Castor
、
JavaBean
、
XMLBean
的時候,就需要我們自己去創建
DeserializerFactory
和
SerializerFactory
。
2
.
DeserializerFactory
和
Deserializer
反序列化工廠是用戶將 XML 轉成 Java 對象的工廠,它維護了一個 Deserializer 對象,該對象才是真正去做反序列化工作的類。
我們現在創建自己的
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);
?}
}
工廠類的實現比較簡單,我們先繼承 BeanDeserializerFactory 類,然后復寫它的 getDeserializerAs 方法,返回相應的 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
文檔轉成
EMF
模型。
我們繼承
DeserializeImpl
類,然后復寫它的
onEndElement
方法。
??????? public ? void ?onEndElement(String?namespace,?String?localName,
?????????????????????DeserializationContext?context)? throws ?SAXException?{
??????????????…….
}
}
在
onEndElement
方法中的參數有一個
DeserializationContext
對象,我們可以通過它獲得
XML
文檔片段:
該
Document
就是得到的
XML
片段。
然后我們通過
EMF
提供的
Resource
對象將
XML
文檔進行反序列化(這里我自己寫了一個創建
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
轉成
String
,然后通過
ByteArrayInputStream
傳給
resource,resource
在
load
后會生成對應的數據對象,并且我們可以通過
resource
獲得:
value? = ?sdoValue;
這里需要注意的是,如果我們生成的
EMF
模型是通過
XSD
來生成的,那反序列化后得到的應該是一個
DocumentRoot
對象,該對象可能并不是我們想得到的,比如:
< student? name =”me”/>
得到的對象并是不
Student
對象,而是一個
DocumentRoot
,而
Student
對象是包含在
DocuementRoot
對象的子對象中。
但是如果是直接通過
Ecore
模型生成的則不會有
DocumentRoot
對象。這里如何去判斷得到的對象是不是
DocumentRoot
需要讀者進一步去看看
EMF
,這里我沒有給出通用的手段解決,只是根據我本身程序的需求去獲得的:
????List?contents? = ?((EObject)sdoValue).eContents();
?? ? for ?(Iterator?iter? = ?contents.iterator();?iter??.hasNext();)?{
?????????????Object?element? = ?(Object)?iter.next();
??????????? if (valueVlazz.isInstance(element)){
??????????????????????value? = ?element;
?????????????????????? break ;
????????????}
????}
?}
這里需要注意,對象
value
并不是
EMFDeserializer
自己定義的字段,而是
DeserializerImpl
的字段,該字段就是
Axis
反序列化后的對象值引用字段。
3.???
Serializer
和
SerializerFactory
SerializerFactory
的工作和
DeserializerFactory
工作類似,返回一個
Serializer
對象,它是真正去將對象序列化成
XML
的類。
SerializerFactory
比較簡單,這里就不詳細介紹了:
????????? 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;
???????}
}
我們需要實現三個方法:
1)?
serialize
???2)? getMechanismType
???3)?
writeSchema
writeSchema
方法需要返回一個
XML Schema
的
Element
對象,該
XML Schema
是指我們所用的
EMF
模型對應的
XML Schema
,我采用的
EcoreXMLSchemaBuilder
類就可以將
EPackage
對象轉換成為一個
Schema Element
。不過在這里我發現好像
Axis
對這個方法并不是說非用不可,我也就沒有實現,直接返回的是
NULL
getMechanismType
方法很簡單
??? return ?Constants.AXIS_SAX;
}
這樣就可以了
最重要的是 serialize 方法,這個方法就是將對象進行序列化的方法:
?????????????????????SerializationContext?context)? throws ?IOException?{
??????????????…..
}
首先要將傳入的 value 序列化成一個 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
流中,現在我們需要將這段
XML
寫到
SerializationContext
對象中:
?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();
這樣我們就完成了對對象的序列化。
4.
修改
wsdd
文件
當我們使用
Axis
提供的
WSDL2Java
工具類時,
Axis
會自動給我們生成一個
wsdd
文件,而且當它發現定義的
Operation
中涉及到了復雜類型數據,
Axis
會自動加上
typeMapping
元素,但是它默認給這個元素上定義的
Deserializer , Serializer
是針對
JavaBean
的,所以如果我們的類是是
EMF
,只要將
typeMapping
的類型改成
EMFSerializerFactory
以及
EMFDeserializerFactory
就可以了。
5.
總結
上面是小弟的一點愚見,請各位看官多提意見