前言:上一篇介绍了手动写客户端的axis1.4的应用实例,那个例子是没有问题的,但细心的同志们会发现,生成的wsdl文件是有问题的,比较刺眼的关键字是 ArrayOf_xsd_anyType 这个表明根本不认识list,而且list里放入的对象也没有在该WSDL文件里描述,这样带来的问题就是如果只根据WSDL文件来生成客户端,比如用axis1.4的wsdl2java命令
D:\develop_tools\axis-1_4\lib>java -cp .;axis.jar;jaxrpc.jar;saaj.jar;wsdl4j-1.5.1.jar;commons-discovery-0.2.jar;commons-logging-1.0.4.jar;log4j-1.2.8
.jar org.apache.axis.wsdl.WSDL2Java http://localhost:8091/bjchannel/services/EsopWBService1?wsdl
示例如上,的话,生成的类明显少了一个,就是list里放入的MenuNodeInterface类,这个在WSDL里根本没有体现
而且奇怪的是假如用list的话,如果添加了list的add方法,比如public void addMenuNodeInterface(MenuNodeInterface obj){list.add(obj);}(伪代码)的话,在生成的WSDL里就会有MenuNodeInterface的体现,但集合还是没有。这个看看AXIS的源码就明白了.
关于这个问题,首先参看axis1.4的官方文档user-guide.pdf,这个我在附件里上传上来,查看里面的
1.6.3里的1.6.3.1项,说的很清楚,由于LIST这些集合类和其他语言不通用,所以需要当作CUSTOM类自己做映射在service-config.xml里,那就麻烦了,加入实现类是ArrayList的话,还需要把相应的jar包加进来做映射;
所以后面有一句关键的:The most reliable way to send aggregate objects is to use arrays
有感觉没,对了,就是用[]数组来代替接口里需要的属性和返回值。
废话不说了,上代码
1:返回结果类
package com.asiainfo.boss.channel.channelservices; import java.io.Serializable; public class EsopResult1 implements Serializable{ /** * seriaId */ private static final long serialVersionUID = -1922115715606536898L; /** * 0:成功 1:失败 */ private Short returnCode=1; //一般不用语言特定的集合类,统一用数组代替 //private List<MenuNodeInterface> sysMenuNodeList; private MenuNodeInterface[] sysMenuNodeList; private String errorMsg; // public EsopResult1(){ // sysMenuNodeList=new ArrayList<MenuNodeInterface>(); // sysMenuNodeList.add(new MenuNodeInterface()); // // } // public EsopResult1(){ sysMenuNodeList=new MenuNodeInterface[]{new MenuNodeInterface()}; } public Short getReturnCode() { return returnCode; } public void setReturnCode(Short returnCode) { this.returnCode = returnCode; } // public List<MenuNodeInterface> getSysMenuNodeList() { // return sysMenuNodeList; // } // // public void setSysMenuNodeList(List<MenuNodeInterface> sysMenuNodeList) { // this.sysMenuNodeList = sysMenuNodeList; // } //如果用list的话,还不光需要有list的set和get方法,还必须有addlist的方法,这样生成的wsdl才能包含list里的内容对象 //不过即使这样,还是会有问题,总之用数组代替就对了 public MenuNodeInterface[] getSysMenuNodeList() { return sysMenuNodeList; } public void setSysMenuNodeList(MenuNodeInterface[] sysMenuNodeList) { this.sysMenuNodeList = sysMenuNodeList; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } }
2:手动客户端调用测试类
package com.asiainfo.boss.channel.channelservices; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.XMLType; import org.apache.axis.encoding.ser.BeanDeserializerFactory; import org.apache.axis.encoding.ser.BeanSerializerFactory; public class EsopWBClient1 { public static void main(String...args){ getResult(); } public static void getResult(){ try { String endpoint = "http://localhost:8091/bjchannel/services/EsopWBService1"; Long opId = new Long(1009); Long orgId = new Long(1000); Service service = new Service(); Call call = (Call) service.createCall(); QName qn = new QName("urn:EsopWBService1","EsopResult1"); QName qn1 = new QName("urn:EsopWBService1","MenuNodeInterface"); //注册 bean call.registerTypeMapping(EsopResult1.class, qn, new BeanSerializerFactory(EsopResult1.class, qn), new BeanDeserializerFactory(EsopResult1.class, qn)); call.registerTypeMapping(MenuNodeInterface.class, qn1, new BeanSerializerFactory(MenuNodeInterface.class, qn1), new BeanDeserializerFactory(MenuNodeInterface.class, qn1)); call.setTargetEndpointAddress(new java.net.URL(endpoint)); call.setOperationName(new QName("EsopWBService1","qryMenuNodeInfoList")); // Object[] sss=new Object[2]; // sss[0]=i1; // sss[1]=i2; //EsopResult1 ret = (EsopResult1) call.invoke("qryMenuNodeInfoList",new Object[]{i1,i2}); //以下两个参数必须加,不然后报数组越界异常,因为源码里的operation为的params需要手动设置 //invoke只负责往里传递数,不管原来方法参数的初始化,以下两句表明调用的方法需要初始化两个参数 call.addParameter("opId", XMLType.XSD_LONG, ParameterMode.IN); call.addParameter("orgId", XMLType.XSD_LONG, ParameterMode.IN); EsopResult1 ret = (EsopResult1) call.invoke(new Object[]{opId,orgId}); System.out.println("the operation result following:"); System.out.println("ErrorMsg = " + ret.getErrorMsg()); System.out.println("ReturnCode = " + ret.getReturnCode()); // 这是用list做属性的客户端写法,没有问题,问题只会出现在wsdl的生成上,因为手写客户端在前面手动 // 注册了list里的内容对象,所以会取到,但是生成的wsdl里是没有的,所以依赖wsdl的wsdl2java生成的 // 客户端程序就有问题了。 // System.out.println("MenuNodeList().size() = " + ret.getSysMenuNodeList().size()); // List<MenuNodeInterface> reList=ret.getSysMenuNodeList(); //以下是数组形式的调用 System.out.println("MenuNodeList().length = " + ret.getSysMenuNodeList().length); MenuNodeInterface[] reList=ret.getSysMenuNodeList(); for(MenuNodeInterface mni : reList){ System.out.println("菜单名称:"+mni.getS_Caption()); } } catch (Exception e) { e.printStackTrace(); } } }
其他的类参照上一篇文章,没有修改
配置文件也没有任何变化
OK,附件是我用wsdl2java生成的客户端类,和自己写的测试调用类,打包上传了,老规矩,代码里的报名和有些配置名字自己修改,我就不去除了
参考文章
http://forums.sun.com/thread.jspa?threadID=5405862
http://www.javalobby.org/java/forums/t84343.html