I need to call a SOAP service that returns an attachment.
The XSD that defines the "attached" data is
<xs:complexType name="transferableFileData">
<xs:complexContent>
<xs:extension base="tns:transferableFile">
<xs:sequence>
<xs:element name="fileData" type="xs:base64Binary" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
I am using this plugin in the pom.xml file to generate classes from the WSDL and XSD files
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.15.1</version>
</plugin>
The autogenerated class is this
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "transferableFileData", propOrder = {
"fileData"
})
public class TransferableFileData
extends TransferableFile
{
protected byte[] fileData;
public byte[] getFileData() {
return fileData;
}
public void setFileData(byte[] value) {
this.fileData = value;
}
}
The response is this one from the server:
Cache-Control: max-age=0
Cache-Control: no-cache
Cache-Control: no-store
Server-Timing: ak_p; desc="1705942361025_1611673733_335963847_52691_3577_46_71_-";dur=1
Server-Timing: origin; dur=520
Server-Timing: edge; dur=7
Server-Timing: cdn-cache; desc=MISS
Connection: keep-alive
Set-Cookie: LtpaToken2=Jss03JN+gXMYTd; Path=/; HttpOnly
Expires: Mon
Expires: 22 Jan 2024 16:52:41 GMT
Pragma: no-cache
Content-Length: 2912
Content-Language: en-US
Date: Mon
Date: 22 Jan 2024 16:52:41 GMT
Content-Type: Multipart/Related; boundary="----=_Part_11_2001319686.1705942360849"; type="application/xop+xml"; start-info="text/xml"
SOAPAction: ""
Accept: text/xml
------=_Part_11_2001319686.1705942360849
Content-Type: application/xop+xml; charset=utf-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <0.f4ee8e08bed2d62c7571a5433a8dea327c0877600e72a88b@apache.org>
<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><ns2:downloadPendingFileResponse xmlns:ns2="http://iris.somewhere.cp,/web_services/external/downloadFile" xmlns:ns3="http://iris.somewhere.com/web_services/external/uploadFile"><downloadPendingFileResult><fileExchangeNo>1174649</fileExchangeNo><fileName>TEST00001_2024-01-22-18.46.08.00000_APA.zip</fileName><fileData><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:05ee8e08bed2d62c7571a5433a8dea327c0877600e72a88b@apache.org"/></fileData></downloadPendingFileResult></ns2:downloadPendingFileResponse></soapenv:Body></soapenv:Envelope>
------=_Part_11_2001319686.1705942360849
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <05ee8e08bed2d62c7571a5433a8dea327c0877600e72a88b@apache.org>
�������f��G��v�+p�,����
��K�ɁZt �K�>b�La���^m��_э���1$�t�dqV�A;�ف� F�K�� ��ކO�X![
My Java code goes like this:
if (response instanceof JAXBElement) {
DownloadPendingFileResponse downloadPendingFileResponse = ((JAXBElement<DownloadPendingFileResponse>) response).getValue();
if(downloadPendingFileResponse == null) {
and later
final TransferableFileData transferableData = response.getDownloadPendingFileResult();
...
byte[] bytes = transferableData.getFileData();
log.info("length {}", bytes.length);
However the length is always zero. It seems that I cannot get the file properly.
What I noticed is that the WSDL defines the fileData element as base64Binary and the POJO has them as byte[]. It seems that the data stream isn't unmarhsaled. Any idea how to resolve this issue?
I got the exact same XSD on a WSDL service
<complexType name="myType">
<sequence>
...
<element name="myFile" type="xsd:base64Binary"/>
...
</sequence>
</complexType>
This get generated as by the org.apache.cxf:cxf-codegen-plugin
:
@XmlElement(required = true)
protected byte[] myFile;
But in order to do the unmarshalling, I had to set a XSLT to jaxws:feature
spring client in order to tell CXF to understand the href
in the response (content of file transform.xsl
as below) :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" >
<xsl:key name="multiref-by-id" match="multiRef" use="@id"/>
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="@*|*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(@href, '#')]">
<xsl:copy>
<xsl:apply-templates select="@* |
key('multiref-by-id', substring-after(@href, '#'))/@* |
key('multiref-by-id', substring-after(@href, '#'))/node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@href[starts-with(., '#')] | multiRef[@id] | @soapenc:root"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
And this is the bean defined in XML Spring Config :
<bean id="xsltFeature" class="org.apache.cxf.feature.transform.XSLTFeature">
<property name="inXSLTPath" value="transform.xsl" />
<property name="outXSLTPath" value="transform.xsl" />
</bean>
<jaxws:client id="myService" serviceClass="my.web.Service" address="myurl">
<jaxws:features>
<ref bean="xsltFeature" />
</jaxws:features>
</jaxws:client>
By doing so, I'm able to read the content of the attached file by the getter of myFile
in Java without additional config.
I think you can adapt this in order to make it work in your own application context.