服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

axis序列化/反序列化器开发指南


  前言
  
  axis是apache组织推出的soap引擎,axis项目是apache组织著名的soap项目的后继项目。axis为开发者提供了大量的序列化/反序列化器,能够基本满足大部分应用。但在某些情况下,对特定的对象,现有的序列化/反序列化器不能胜任,于是只有开发人员自己实现专用于此对象的序列化/反序列化器插入到axis中来完成序列化工作。考虑到web service是一门新兴技术,中文资料大多是泛泛的讲解,关于序列化/反序列化器的开发鲜有较为深入的介绍,本文提供一份较为完整的开发指南,并提供了一个十分有用的实现,即序列化jdom模型的element,使其可以通过web 服务在网络上传输,我想这一扩展是许多采用jdom作为xml解析工具的开发人员都梦寐以求的功能。通过本文的介绍和实例,希望能起到抛砖引玉的作用,读者在阅读完本文之后可以轻松的实现针对于任何非符合bean规范的对象的序列化/反序列化器。
  
  本文所面对的读者需要有一定的使用axis做web服务开发的开发经验,因此关于如何axis的基础知识并不在本文的介绍范围,如果读者对此感兴趣,可以参考本文最后的参考资料部分,去相应的网站进行学习。
  
  序列化/反序列化器简介
  
  序列化/反序列化器在英文中的对应翻译是serializer/deserializer,一个序列化器的功能是遵循一定的映射规则和编码风格,将一种类型的java对象通过某种特定的机制,转换成为xml描述的形式;反序列化器的功能是序列化器所做工作的逆操作,两者相辅相成,成对出现。axis中的序列化/反序列化器采用设计范式中的工厂模式,每一个serializer唯一对应一个serializerfactory;每一个deserializer唯一对应一个deserializerfactory。一种类型的java对象具体要采用哪个序列化/反序列化器需要在提供web服务的服务器和调用web服务的客户端分别配置,关于这一部分如何配置,我将在本文后面的内容中进行详细介绍。axis已经为开发者提供了丰富的序列化/反序列化器,对于java的基本数据类型,绝大部分常用的容器类(比如数组类型,vector类型等)都提供了实现,特别是提供了对w3c的dom对象(比如document, element等)和符合bean规范的java对象提供了功能完善的序列化/反序列化器,因此我们在需要的时候只要在配置文件中配置一下就可以直接使用。如果对象中包含其它类型的对象,比如vector中包含一组bean对象,axis会自动叠代的调用序列化器,最终拼装成唯一的xml表述。在还原成java对象时,也遵循这样的叠代操作逆向进行。关于axis到底内置了哪些序列化/反序列化器,您可以参照axis的api文档中包org.apache.axis.encoding.ser下的类的名称"望文生义"的了解一下,在以后的开发中做到心中有数。但对于一些特殊类型的对象(其实我们自己开发的很大一部分类都是这种特殊类型的对象,很少有绝对符合bean规范的),需要通过web服务进行传递,我们不得不开发自己的序列化/反序列化器。
  
  开发篇
  
  开发自己的序列化/反序列化器是一个激动人心的工作,但是却并不复杂,需要做的事情包括实现名成为org.apache.axis.encoding的包中的serializerfactory,serializer,deserializerfactory和deserializer这四个接口。下面我将结合一个实例来讲解序列化/反序列化器的开发方法,希望读者能够一边参看本文提供的源代码一边学习。
  
  jdom作为一款比较"另类"的xml解析工具(因为它不符合w3c的dom模型,自己另立一套)默默地占领着java世界里的xml解析器的半壁江山,由于其简洁的设计和方便灵活的api调用,已经渐渐成为了许多开发人员在进行xml开发的首选。但是axis是建立在w3c的dom模型的基础之上,师出名们正派,自然不屑与jdom为伍。因此当开发人员想将自己已经写好的基于jdom的应用模块采用web服务的方式发布的时候,不可避免的会遇到如何将jdom模型下的对象如document, element等序列化的问题。在软件工程师不会自己扩展axis的序列化/反序列化器的时候,我们只能有两个办法达到这个目的,第一个就是更改以前应用模块内的api设计,使暴露的入口参数和返回值参数都是w3c的对象类型,但这种做法并不现实,因为这一应用模块往往不是独立存在,牵一发将动全身,导致旧有系统架构的崩塌;另一种做法就是为这个模块做一个代理类,它做的工作就对外接收或返回dom模型的对象,对内转换成jdom模型的对象,然后转发给应用模块,繁琐且效率低下。当我们向axis注入了针对于jdom模型的序列化/反序列化器后,这一工作便可以由axis代劳了。下面我们将逐个开发这四个类:
  
  jdomelementserializerfactory
  
  jdomelementserializerfactory是一个工厂类,需要通过某种机制注册到axis引擎(具体方法见下面"服务器端应用篇");axis通过调用它,来实例化jdomelementserializer。axis 提供了baseserializerfactory,这个类是一个抽象类,并实现其中包含了一些可重用的代码。我们自己开发的工厂类只需简单继承这个类就可以。构造函数中需要调用父类的构造函数将序列器类下面是它的源代码:
  
  package org.apache.axis.encoding.ser;
  
  public class jdomelementserializerfactory
  extends baseserializerfactory {
  
  public jdomelementserializerfactory() {
  super(jdomelementserializer.class);
  }
  }
  
  jdomelementserializer
  
  jdomelementserializer实现org.apache.axis.encoding.serializer接口,其核心api是serialize(),我们需要在这个方法的内部完成对jdom模型的element的序列化工作,序列化的结果要保存在入口参数传入的序列化上下文对象(serializationcontext)中:
  
  public void serialize(qname name, attributes attributes, object value,
  serializationcontext context) throws java.io.ioexception {
  
  if (!(value instanceof element))
  throw new ioexception(
  messages.getmessage("cant serialize object"));
  
  //获取符合jdom的element对象
  element root=(element)value;
  
  //输出到stringwriter
  xmloutputter outputter=new xmloutputter();//创建一个jdom的xml输出器
  stringwriter sw=new stringwriter();
  outputter.output(root,sw);
  
  //用支持w3c的dom模型的xerces解析器解析文本流
  domparser parser=new domparser();//创建一个dom的xml解析器
  try {
  parser.parse(new org.xml.sax.inputsource(
  new java.io.stringreader(sw.tostring())));
  }catch (exception ex) {
  throw new java.io.ioexception("序列化时产生错误");
  }
  
  //获取符合dom模型的element对象
  org.w3c.dom.element w3c_root =
  parser.getdocument().getdocumentelement();
  
  //放入序列化上下文对象中
  context.startelement(name, attributes);
  context.writedomelement(w3c_root);
  context.endelement();
  }
  
  jdomelementdeserializerfactory
  
  反序列化器的工厂类同序列化器的工厂类一样的设计,在此不在赘述。代码:
  
  package org.apache.axis.encoding.ser;
  
  public class jdomelementdeserializerfactory
  extends basedeserializerfactory {
  
  public jdomelementdeserializerfactory() {
  super(jdomelementdeserializer.class);
  }
  
  }
  
  jdomelementdeserializer
  
  用过sax解析xml的读者,对反序列化的实现比较容易理解,反序列化也采用了消息触发的机制,我们只需继承org.apache.axis.encoding.deserializerimpl类,并覆盖其中的onendelement方法:
  
  /**
  * 在元素结束触发反序列化的方法
  * @param namespace string 命名空间
  * @param localname string 本地名称
  * @param context deserializationcontext 反序列化上下文
  * @throws saxexception
  */
  public void onendelement(string namespace, string localname,
  deserializationcontext context) throws saxexception {
  
  try {
  //从反序列化上下文对象中获取原始的消息元素
  messageelement msgelem = context.getcurelement();
  if (msgelem != null) {
  messagecontext messagecontext = context.getmessagecontext();
  boolean currentelement = (boolean) messagecontext.getproperty(
  deserialize_current_element);
  
  //如果当前的消息元素本身需要反序列化
  if (currentelement != null && currentelement.booleanvalue()) {
  org.w3c.dom.element element = msgelem.getasdom();
  org.jdom.input.dombuilder db=new org.jdom.input.dombuilder();
  value=db.build(element);
  messagecontext.setproperty(deserialize_current_element,
  boolean.false);
  return;
  }
  
  //反序列化消息元素中的消息体
  java.util.arraylist children = msgelem.getchildren();
  if (children != null) {
  
  //取得消息体
  msgelem = (messageelement) children.get(0);
  if (msgelem != null) {
  org.w3c.dom.element ret = msgelem.getasdom();
  org.jdom.input.dombuilder db=new org.jdom.input.dombuilder();
  
  //用dombuilder将dom模型的element,转换成jdom模型的element
  value=db.

扫描关注微信公众号