I am receiving a SOAP request from some legacy code, and dealing with it using JAX-WS generated objects from the same WSDL the legacy code uses, but I am getting an Unmarshalling Error: unexpected element error when I process the request.
The WSDL part for this request is as follows: (Please note “schema” has replaced all the actual schema locations for our WSDL)
<xsd:complexType name="Administrate">
<xsd:sequence>
<xsd:element name="AdminOperation" type="typens:AdminOperation" maxOccurs="unbounded" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="Administrate" type="typens:Administrate"/>
<xsd:complexType name="AdministrateResponse">
<xsd:sequence>
<xsd:element name="Status" type="typens:SoapResponseStatus"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="AdministrateResponse" type="typens:AdministrateResponse"/>
<xsd:complexType name="AdminOperation">
<xsd:sequence>
<xsd:choice>
<xsd:element name="Transaction" type="typens:Transaction" minOccurs="0"/>
<xsd:element name="CreateUser" type="typens:CreateUser" minOccurs="0"/>
<xsd:element name="DeleteUser" type="typens:DeleteUser" minOccurs="0"/>
<xsd:element name="UpdateUser" type="typens:UpdateUser" minOccurs="0"/>
<xsd:element name="CreateGroup" type="typens:CreateGroup" minOccurs="0"/>
<xsd:element name="DeleteGroup" type="typens:DeleteGroup" minOccurs="0"/>
<xsd:element name="UpdateGroup" type="typens:UpdateGroup" minOccurs="0"/>
<xsd:element name="CreateChannel" type="typens:CreateChannel" minOccurs="0"/>
<xsd:element name="DeleteChannel" type="typens:DeleteChannel" minOccurs="0"/>
<xsd:element name="UpdateChannel" type="typens:UpdateChannel" minOccurs="0"/>
<xsd:element name="CreateRole" type="typens:CreateRole" minOccurs="0"/>
<xsd:element name="DeleteRole" type="typens:DeleteRole" minOccurs="0"/>
<xsd:element name="UpdateRole" type="typens:UpdateRole" minOccurs="0"/>
<xsd:element name="CreateFileType" type="typens:CreateFileType" minOccurs="0"/>
<xsd:element name="DeleteFileType" type="typens:DeleteFileType" minOccurs="0"/>
<xsd:element name="UpdateFileType" type="typens:UpdateFileType" minOccurs="0"/>
<xsd:element name="CreateFolder" type="typens:CreateFolder" minOccurs="0"/>
<xsd:element name="DeleteFile" type="typens:DeleteFile" minOccurs="0"/>
<xsd:element name="MoveFile" type="typens:MoveFile" minOccurs="0"/>
<xsd:element name="CopyFile" type="typens:CopyFile" minOccurs="0"/>
<xsd:element name="UpdateFile" type="typens:UpdateFile" minOccurs="0"/>
<xsd:element name="DeleteJob" type="typens:DeleteJob" minOccurs="0"/>
<xsd:element name="DeleteJobNotices" type="typens:DeleteJobNotices" minOccurs="0"/>
<xsd:element name="UpdateJobSchedule" type="typens:UpdateJobSchedule" minOccurs="0"/>
<xsd:element name="UpdateVolumeProperties" type="typens:UpdateVolumeProperties" minOccurs="0"/>
<xsd:element name="UpdateOpenSecurityCache" type="typens:UpdateOpenSecurityCache" minOccurs="0"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
and the request sent:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsd="http://www.w3.org/2000/10/XMLSchema" xmlns="schema">
<SOAP-ENV:Header>
<AuthId>7</AuthId>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<Administrate>
<UpdateFile>
<SetPermissions>
<Permission SOAP-ENC:arrayType="Permission[1]">
<UserName>username</UserName>
<AccessRight>rights</AccessRight>
</Permission>
</SetPermissions>
<NameList>
<String>folder1</String>
<String>folder1/folder2</String>
<String>folder1/folder2/file.ext</String>
</NameList>
</UpdateFile>
</Administrate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
But I get the following error from my code:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Unmarshalling Error: unexpected element
(uri:"schema", local:"UpdateFile"). Expected elements
are <{schema}AdminOperation> </faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
The Administrate JAX-WS generated object just contains an ArrayList of AdminOperations with a getter,
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Administrate", propOrder = {
"adminOperation"
})
public class Administrate {
@XmlElement(name = "AdminOperation")
protected List<AdminOperation> adminOperation;
/**
* Gets the value of the adminOperation 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 adminOperation property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getAdminOperation().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link AdminOperation }
*
*
*/
public List<AdminOperation> getAdminOperation() {
if (adminOperation == null) {
adminOperation = new ArrayList<AdminOperation>();
}
return this.adminOperation;
}
}
But judging from the legacy request sent and from the WSDL, this operation tag is replaced with choice of operations, e.g. updatefile etc right?
As I cannot change the legacy request or legacy WSDL, I am unsure as to how to proceed. Any help would be greatly appreciated, so thanks in advance!
Your suspicion is correct. In this case, the client is actually sending a request that does not conform to the provided schema.
Since you have no control of the client code and apparently must accommodate the client, my hope is that it is the only client for this service. The simplest path-forward would be to adjust the service to the contract for which the client has actually been built. You could manually tweak the schema to indicate that UpdateFile is a child of Administrate, then regen the relevant objects or (to not bother with regen of objects) tweak the Administrate java object annotations to reflect FileUpdate as first-level child:
…
@XmlType(name = “Administrate”, propOrder = {
“updateFile”
})
public class Administrate {
…
Due diligence would be to also recognize the other forms of request (do they conform to the contract) to ensure no further breakage when adapting the service endpoint.