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.
总结
上面是小弟的一点愚见,请各位看官多提意见