我有一个小应用程序,用于查询我们的SharePoint服务器的Web服务界面,以获取组的所有用户的列表。 我可以看到原始HTTP响应将与列出的所有用户一起返回,但JAX-WS响应对象(在NetBeans 6.9下创建)仅包含空白的Group Name String值。 HTTP响应中没有所有用户名的跟踪。
任何人都知道为什么JAX-WS没有正确读取SOAP响应?
WSDL要发布很长时间,但可以从各个位置(包括此站点)广泛访问: http://www.hezser.de/_vti_bin/UserGroup.asmx?wsdl
这是原始HTTP响应的开始:
---[HTTP response - http://{server}/_vti_bin/usergroup.asmx - 200]---
null: HTTP/1.1 200 OK
Cache-control: private, max-age=0
Content-type: text/xml; charset=utf-8
Content-length: 136738
X-powered-by: ASP.NET
Server: Microsoft-IIS/6.0
Date: Wed, 22 Sep 2010 20:53:12 GMT
X-aspnet-version: 2.0.50727
Set-cookie: WSS_KeepSessionAuthenticated=80; path=/
Microsoftsharepointteamservices: 12.0.0.6303
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetUserCollectionFromGroupResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/"><GetUserCollectionFromGroupResult><GetUserCollectionFromGroup><Users><User ID="201" Sid="S-1-5-21-1545385408-2720673749-3828181483-1245" ....
答案 0 :(得分:3)
在生成存根之前,您需要手动编辑UserGroup.wsdl。您需要将processContents='skip'
添加到定义响应的<s:any>
标记。
<s:element name="GetUserCollectionFromGroupResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetUserCollectionFromGroupResult">
<s:complexType mixed="true">
<s:sequence>
<!-- Added the "processContents" attribute below -->
<s:any processContents='skip' />
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
然后,在处理响应时,JAXB将子节点作为DOM元素返回:
UserGroup service = new UserGroup();
UserGroupSoap port = service.getUserGroupSoap();
GetUserCollectionFromGroupResult usersCollection = port.getUserCollectionFromGroup(Settings.usersGroup);
List<Object> content = usersCollection.getContent();
org.w3c.dom.Element usersElement = (org.w3c.dom.Element) content.get(0);
为什么会这样?
问题是由多种条件引起的:
一个。 Web服务返回的响应包含<GetUserCollectionFromGroup>
标记:
<GetUserCollectionFromGroupResult>
<GetUserCollectionFromGroup>
<Users>
<User ID="4" Name="User1_Display_Name" />
<User ID="5" Name="User2_Display_Name" />
</Users>
</GetUserCollectionFromGroup>
</GetUserCollectionFromGroupResult>
B中。嵌入在WSDL中的模式将<GetUserCollectionFromGroup>
定义为包含一个子项<groupName>
(这是用于发出请求的元素):
<s:element name="GetUserCollectionFromGroup">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="groupName" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
℃。 JAXB尊重processContents
的{{1}}属性(请参阅Mapping of <xs:any />)。当<xs:any>
时,JAXB尝试根据它们所属的命名空间匹配(和编组)子元素。
d。 processContents='strict'
的WSDL架构定义包括<GetUserCollectionFromGroupResult>
:
<xs:any>
电子。省略<s:element name="GetUserCollectionFromGroupResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetUserCollectionFromGroupResult">
<s:complexType mixed="true">
<s:sequence>
<s:any/>
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
时,默认值为processContents
。
因此,当JAX-WS / JAXB处理来自Web服务的结果时,它会尝试使用模式对strict
的子进程进行编组。子项在响应中显示为与请求属于同一名称空间。处理<GetUserCollectionFromGroupResult>
元素时,会将其编组为<GetUserCollectionFromGroup>
元素请求中使用的同一类的实例。因此,您实际上无法访问<GetUserCollectionFromGroup>
元素。
我搜索过高和低,我能找到的唯一解决方案是以太(a)编辑WSDL,如本答案开头所述,或(b)编辑生成的存根。不理想,但在这种情况下是不可避免的。
有关<Users>
架构元素(以及<xs:any>
属性)的更多信息,请访问MSDN here。
答案 1 :(得分:0)
您的问题有点难以回答,因为我们没有看到您正在使用的生成的客户端,也没有看到调用时的调试/错误消息,但我会尝试。您的WSDL看起来有效,如果您的JAX-WS工具堆栈能够创建客户端(具有适当的Java类)并且能够正确调用端点,那么到目前为止您做得很好。
查看HTTP响应和您的WSDL,您的SOAP请求是 GetUserCollectionFromGroup 调用。看看 GetUserCollectionFromGroupResponse 的XML-Schema定义(在WSDL中)我很困惑一件事:
<s:element name="GetUserCollectionFromGroupResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetUserCollectionFromGroupResult">
<s:complexType mixed="true">
<s:sequence>
<s:any />
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
WSDL基本上表示您的调用可以返回任何类型的XML。您从Web服务中获得的是一个XML片段,如:
<users><user ID="201" Sid="" /></users>
当然这符合任何类型的XML的描述,但我认为您生成的客户端无法理解它。现在,我没有使用NetBeans 6.9的jax-ws工具堆的经验,但是你应该以这样的方式配置WSDL到客户端的生成,它将这个'any'转换为java XML-Element或java XML-节点对象。
此调用生成的代码是什么样的?它真的认为你得到 String用户吗?
答案 2 :(得分:0)
感谢您的回复。你是对的我应该发布生成的代码,但调用和响应是如此简单,我没有想到它。 简化了通话
System.setProperty("com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump", "true");
GetUserCollectionFromGroupResult usersCollection = null;
Object o = null;
UserGroup service = new UserGroup();
UserGroupSoap port = service.getUserGroupSoap();
usersCollection = port.getUserCollectionFromGroup(Settings.usersGroup);
返回的usersCollection只包含一个元素,即“groupName”,其值为“null”。
不幸的是,微软似乎喜欢在几乎所有的WSDL定义中使用ANY元素。我有几个工作,包括身份验证,Web,列表,版本,但这个不会去。
我认为可以覆盖默认的接收器代码,但是今天早些时候我决定编写自己的简单SOAP客户端可能更容易,而不是试图找出修复JAX-WS接收器。因此即使它可能不是最正确的方法,它也完成了工作。 这是所有恐怖的代码。
我是Java的新手,所以对我很轻松; - )
HashMap<String, String> users = null;
String SOAPUrl = Settings.userListWebServiceURL;
String SOAPAction = "http://schemas.microsoft.com/sharepoint/soap/directory/GetUserCollectionFromGroup";
// Create the connection.
URL url = new URL(SOAPUrl);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" ?><S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Body><GetUserCollectionFromGroup xmlns=\"http://schemas.microsoft.com/sharepoint/soap/directory/\"><groupName>");
sb.append(Settings.usersGroup);
sb.append("</groupName></GetUserCollectionFromGroup></S:Body></S:Envelope>");
byte[] b = sb.toString().getBytes("UTF-8");
// Set the appropriate HTTP parameters.
httpConn.setRequestProperty("Content-Length", String.valueOf( b.length ) );
httpConn.setRequestProperty("Content-Type","text/xml; charset=utf-8");
httpConn.setRequestProperty("SOAPAction",SOAPAction);
httpConn.setRequestMethod( "POST" );
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
// Everything's set up; send the XML that was read in to b.
OutputStream out = httpConn.getOutputStream();
out.write( b );
out.flush();
out.close();
// Setup to receive the result and convert stream to DOM Document
DOMParser parser = new DOMParser();
InputStreamReader in = new InputStreamReader(httpConn.getInputStream());
InputSource source = new InputSource(in);
parser.parse(source);
org.w3c.dom.Document d = parser.getDocument();
in.close();
httpConn.disconnect();
// Read the DOM and contruct a Hashmap with username to e-mail mapping.
NodeList nl = d.getElementsByTagName("User");
users = new HashMap<String, String>();
for (int i = 0; i < nl.getLength(); i++) {
NamedNodeMap attr = nl.item(i).getAttributes();
users.put(attr.getNamedItem("LoginName").getNodeValue(), attr.getNamedItem("Email").getNodeValue());
}