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
?
class
?EMFDeserializerFactory?
extends
?BeanDeserializerFactory?{
??
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
类即可。
?
public
?
class
?EMFDeserializer?
extends
?DeserializerImpl?{
???????
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
?
class
?EMFDeserializer?
extends
?DeserializerImpl?{
???????
public
?
void
?onEndElement(String?namespace,?String?localName,
?????????????????????DeserializationContext?context)?
throws
?SAXException?{
??????????????…….
}
}
在
onEndElement
方法中的参数有一个
DeserializationContext
对象,我们可以通过它获得
XML
文档片段:
Document?doc?
=
?context.getCurElement().getAsDocument();
该
Document
就是得到的
XML
片段。
然后我们通过
EMF
提供的
Resource
对象将
XML
文档进行反序列化(这里我自己写了一个创建
XMLResourceImpl
的工厂类,读者可以在文章后面下载代码):
org.apache.xml.serialize.DOMSerializerImpl?s1?
=
?
???? 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
获得:
sdoValue?
=
?resource.getContents().get(
0
);
value?
=
?sdoValue;
这里需要注意的是,如果我们生成的
EMF
模型是通过
XSD
来生成的,那反序列化后得到的应该是一个
DocumentRoot
对象,该对象可能并不是我们想得到的,比如:
<?
xml?version=””?encoding=”UTF-8”
?>
<
student?
name
=”me”/>
得到的对象并是不
Student
对象,而是一个
DocumentRoot
,而
Student
对象是包含在
DocuementRoot
对象的子对象中。
但是如果是直接通过
Ecore
模型生成的则不会有
DocumentRoot
对象。这里如何去判断得到的对象是不是
DocumentRoot
需要读者进一步去看看
EMF
,这里我没有给出通用的手段解决,只是根据我本身程序的需求去获得的:
if
(sdoValue?
instanceof
?EObject){
????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
?
class
?EMFSerializerFactory?
extends
?BaseSerializerFactory?{
?????????
public
?EMFSerializerFactory(Class?javaType,?QName?xmlType)?{
???????????????
super
(EMFSerializer.
class
,?xmlType,?javaType);
???????}
}
?
Serializer
类需要继承
Serializer
接口:
public
?
class
?EMFSerializer?
implements
?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
方法很简单
public
?String?getMechanismType()?{
???
return
?Constants.AXIS_SAX;
}
这样就可以了
?
最重要的是
serialize
方法,这个方法就是将对象进行序列化的方法:
?
public
?
void
?serialize(QName?name,?Attributes?attributes,?Object?value,
?????????????????????SerializationContext?context)?
throws
?IOException?{
??????????????…..
}
?
首先要将传入的
value
序列化成一个
XML
文档:
?
EPackage?ePackage?
=
?((EObject)?value).eClass().getEPackage();
?????????????????????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.setWriteXMLType(
null
);
?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.
总结
上面是小弟的一点愚见,请各位看官多提意见
posted on 2006-08-30 18:23
Dart 阅读(276)
评论(0) 编辑 收藏 收藏至365Key 所属分类:
SOA 、
EMF