最近遇到一个Axis调用CXF发布的WebService时报错的问题,在此记录一下问题解决的过程。
客户使用Axis调用我方使用CXF发布的WebService报错。报错信息为意外的元素,如下图所示

从报错信息看,WebService端需要的参考类型是<{}arg0>
,而接收到的参数是(uri:"http://tempuri.org/", local:"xmlParameter")
。经过搜索,发现需要在参数上添加注解,显式注明namespace和参数名:@WebParam(name = "xmlParameter", targetNamespace = "http://tempuri.org/")
。修改完成后,本地测试依然报错,如下图所示

有了之前的经验,很快发现需要在方法上添加注解注明action
:@WebMethod(action = "http://tempuri.org/getAllPurchasePlane")
,同时,也针对返回值也添加了注解,注明返回值的namespace
:@WebResult(targetNamespace = "http://tempuri.org/")
。本地使用Axis测试调用成功,故更新至测试系统与客户联调,发现还是报错,但报错信息变为类型转换错误,如下图所示。

根据错误信息查找多次后仍未解决,此时,只好询问客户是否可以提供调用代码。获取调用代码后,发现确实调用代码有所不同,如下图所示。

使用客户提供的调用代码测试确实调用不成功,但WebService确实是按照客户提供的文档发布的,同时发现WebService端返回值类型为String[]
,但调用方接收到的是List
类型,所以导致了转换出错。由此怀疑是不是客户调用方法有问题,但沟通后反馈说其他系统对接过,没有问题,此时问题陷入了死胡同。
面对这种问题,需要看透问题的本质,WebService的调用依靠的是WSDL描述调用属性,既然我们调用不成功,会不会是生成的WSDL有问题呢?按照这个思路,咨询客户获得了一份之前对接成功的系统的WSDL。经过比对,果然发现返回值类型并不是文档中写明的String[]
,而是ArrayOfString
,如下图所示:

经过搜索,很快就找到了ArrayOfString
的源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>
* Java class for ArrayOfString complex type.
* <p>
* The following schema fragment specifies the expected content contained within
* this class.
*
* <pre>
* <complexType name="ArrayOfString">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="string" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ArrayOfString", propOrder = { "string" })
public class ArrayOfString {
@XmlElement(nillable = true)
protected List<String> string;
/**
* Gets the value of the string property.
* <p>
* This accessor method returns a reference to the live list, not a snapshot.
* Therefore any modification you make to the returned list will be present
* inside the JAXB object. This is why there is not a <CODE>set</CODE> method
* for the string property.
* <p>
* For example, to add a new item, do as follows:
*
* <pre>
* getString().add(newItem);
* </pre>
* <p>
* Objects of the following type(s) are allowed in the list {@link String }
*/
public List<String> getString() {
if (string == null) {
string = new ArrayList<String>();
}
return this.string;
}
}
|
最终WebService代码修改如下:
1
2
3
4
5
6
7
8
|
@WebMethod(action = "http://tempuri.org/getAllPurchasePlane")
public @WebResult(targetNamespace = "http://tempuri.org/") ArrayOfString getAllPurchasePlane(
@WebParam(name = "xmlParameter", targetNamespace = "http://tempuri.org/") String xmlParameter) {
ArrayOfString ret = new ArrayOfString();
ret.getString().add("-1");
ret.getString().add("xml格式不正确");
return ret;
}
|
修改代码后,本地测试通过,再和客户联调也验证通过,问题至此解决。
但疑问还没有消除,根据ArrayofString
的源码,其实也只是封装了一个List<String>
,为什么使用Axis调用后的返回值可以转换成String[]
?希望了解的人告知一二。