In this tutorial, we are going to provide an example of a web services-based application that transfers binary data (e.g. content of an arbitrary file) using base64 encoding/decoding approach. The web services library to be used is JAX-WS (Java API for XML Web Services) which is a built-in technology in Java EE family and is also available in Java SE 6 or later.

 

1. Understand how to transfer binary data via web services

In the approach employed by this article, the binary data is embedded directly in the SOAP envelop using base64 text encoding. In other words, the raw binary data is converted to an encoded String which is value of an XML element in the SOAP message. Upon receiving the SOAP message, the receiver decodes the encoded String in order to re-construct the original binary data.

The following picture depicts this process:

SOAP with binary data process

This approach is the simplest way and is only suitable for transferring a small amount of binary data. It becomes very inefficient when transferring a large amount of binary data because the base64 text encoding technique bloats the data by a factor of 1.33x (UTF-8 text encoding) or 2.66x (UTF-16 text encoding) of the original size. Also, the encoding/decoding process slows down the application performance.

This approach is also often referred as “by value” or “inline attachment” method. Now, let’s go through an example application that is used to transfer small binary files.

NOTE: To optimize the binary data transfer, read: Using MTOM to optimize binary data transfer with JAX-WS web services.

 

2. Code the Web Service Endpoint Interface

Let’s define an endpoint interface as follows:

package net.codejava.ws.binary.server;

import javax.jws.WebMethod;
import javax.jws.WebService;

/**
 * A web service endpoint interface.
 * @author www.codejava.net
 *
 */
@WebService
public interface FileTransferer {
	@WebMethod
	public void upload(String fileName, byte[] imageBytes);
	
	@WebMethod
	public byte[] download(String fileName);	
} 
This endpoint defines two web methods, upload() and download() which allows the client to upload/download a file by sending/receiving a chunk of bytes.

 

3. Code the Web Service Endpoint Implementation



Write an implementation for the FileTransferer interface as follows:

package net.codejava.ws.binary.server;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.WebServiceException;

/**
 * A web service implementation of an endpoint interface.
 * @author www.codejava.net
 *
 */
@WebService
public class FileTransfererImpl implements FileTransferer {
	@WebMethod
	public void upload(String fileName, byte[] imageBytes) {
		
		String filePath = "e:/Test/Server/Upload/" + fileName;
		
		try {
			FileOutputStream fos = new FileOutputStream(filePath);
			BufferedOutputStream outputStream = new BufferedOutputStream(fos);
			outputStream.write(imageBytes);
			outputStream.close();
			
			System.out.println("Received file: " + filePath);
			
		} catch (IOException ex) {
			System.err.println(ex);
			throw new WebServiceException(ex);
		}
	}
	
	@WebMethod
	public byte[] download(String fileName) {
		String filePath = "e:/Test/Server/Download/" + fileName;
		System.out.println("Sending file: " + filePath);
		
		try {
			File file = new File(filePath);
			FileInputStream fis = new FileInputStream(file);
			BufferedInputStream inputStream = new BufferedInputStream(fis);
			byte[] fileBytes = new byte[(int) file.length()];
			inputStream.read(fileBytes);
			inputStream.close();
			
			return fileBytes;
		} catch (IOException ex) {
			System.err.println(ex);
			throw new WebServiceException(ex);
		}		
	}
} 
As we can see, the upload() method saves the received bytes array to file specified by the given fileName; and the download() method reads the requested file and returns its content as a bytes array.

 

4. Code the Server Program for Web Services

Let’s create a server program that publishes the above endpoint implementation as follows:

package net.codejava.ws.binary.server;

import javax.xml.ws.Endpoint;

/**
 * A simple web service server.
 * @author www.codejava.net
 *
 */
public class WebServiceServer {

	public static void main(String[] args) {
		String bindingURI = "http://localhost:9898/codejava/fileService";
		FileTransferer service = new FileTransfererImpl();
		Endpoint.publish(bindingURI, service);
		System.out.println("Server started at: " + bindingURI);
	}
} 
Now run this program and we should see the following message in the console.

Server started at: http://localhost:9898/codejava/fileService

The server is now waiting for request. Next, we are going to generate the web service client code. 

 

5. Generating Client Code for Web Services

It’s recommended to use the wsimporttool in order to generate web services client code in Java. Execute the following command at the command prompt:

wsimport -keep -p net.codejava.ws.binary.client http://localhost:9898/codejava/fileService?wsdl

The wsimporttool generates necessary client code and puts .java source files under the package net.codejava.ws.binary.client. Here’s the list of generated files:

    • Download.java
    • DownloadResponse.java
    • FileTransfererImpl.java
    • FileTransfererImplService.java
    • ObjectFactory.java
    • package-info.java
    • Upload.java
    • UploadResponse.java
NOTES: You must ensure that the sever program is running before executing the wsimportcommand.

 

6. Coding the Client Program for Web Services

Based on the generated web services client code, we can write a client program as follows:

package net.codejava.ws.binary.client;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * A client program that connects to a web service in order to upload
 * and download files.
 * @author www.codejava.net
 *
 */
public class WebServiceClient {

	public static void main(String[] args) {
		// connects to the web service
		FileTransfererImplService client = new FileTransfererImplService();
		FileTransfererImpl service = client.getFileTransfererImplPort();
		
		String fileName = "binary.png";
		String filePath = "e:/Test/Client/Upload/" + fileName;
		File file = new File(filePath);
		
		// uploads a file
		try {
			FileInputStream fis = new FileInputStream(file);
			BufferedInputStream inputStream = new BufferedInputStream(fis);
			byte[] imageBytes = new byte[(int) file.length()];
			inputStream.read(imageBytes);
			
			service.upload(file.getName(), imageBytes);

			inputStream.close();
			System.out.println("File uploaded: " + filePath);
		} catch (IOException ex) {
			System.err.println(ex);
		}		
		
		// downloads another file
		fileName = "camera.png";
		filePath = "E:/Test/Client/Download/" + fileName;
		byte[] fileBytes = service.download(fileName);
		
		try {
			FileOutputStream fos = new FileOutputStream(filePath);
			BufferedOutputStream outputStream = new BufferedOutputStream(fos);
			outputStream.write(fileBytes);
			outputStream.close();
			
			System.out.println("File downloaded: " + filePath);
		} catch (IOException ex) {
			System.err.println(ex);
		}
	}
} 
As we can see, this client program connects to the web service then uploads an image file to the service, and finally downloads another image file from the service.

 

7. Test binary data transfer with web services

Running the client program we should see the following output:

File uploaded: e:/Test/Client/Upload/binary.png
File downloaded: E:/Test/Client/Download/camera.png
And here’s the server’s output:

Received file: e:/Test/Server/Upload/binary.png
Sending file: e:/Test/Server/Download/camera.png
Using a monitoring tool such asTCP/IP Monitor in Eclipse IDE, we can spot the SOAP messages delivered along with the request and response as follows:

  • Invoking the upload() method:
    • Client Request:
      GET /codejava/fileService?wsdl HTTP/1.1
      User-Agent: Java/1.7.0_17
      Host: localhost:9898
      Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
      Connection: keep-alive
      
      POST /codejava/fileService HTTP/1.1
      Accept: text/xml, multipart/related
      Content-Type: text/xml; charset=utf-8
      SOAPAction: "http://server.binary.ws.codejava.net/FileTransfererImpl/uploadRequest"
      User-Agent: JAX-WS RI 2.2.4-b01
      Host: localhost:9898
      Connection: keep-alive
      Content-Length: 1971
      
      <?xml version="1.0" ?>
      <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
      	<S:Body>
      		<ns2:upload xmlns:ns2="http://server.binary.ws.codejava.net/">
      			<arg0>binary.png</arg0>
      			<arg1>iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAA....</arg1>
      		</ns2:upload>
      	</S:Body>
      </S:Envelope>
       

    • Server Response (WSDL XML is omitted):
      HTTP/1.1 200 OK
      Transfer-encoding: chunked
      Content-type: text/xml;charset=utf-8
      Date: Fri, 11 Oct 2013 02:48:45 GMT
      
      -- WSDL XML (ommitted for saving space)....
      
      
      HTTP/1.1 200 OK
      Transfer-encoding: chunked
      Content-type: text/xml; charset=utf-8
      Date: Fri, 11 Oct 2013 02:48:45 GMT
      
      <?xml version="1.0" ?>
      <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
      	<S:Body>
      		<ns2:uploadResponse xmlns:ns2="http://server.binary.ws.codejava.net/"/>
      	</S:Body>
      </S:Envelope>
       

  • Invoking the download() method:
    • Client Request:
      POST /codejava/fileService HTTP/1.1
      Accept: text/xml, multipart/related
      Content-Type: text/xml; charset=utf-8
      SOAPAction: "http://server.binary.ws.codejava.net/FileTransfererImpl/downloadRequest"
      User-Agent: JAX-WS RI 2.2.4-b01
      Host: localhost:9898
      Connection: keep-alive
      Content-Length: 218
      
      <?xml version="1.0" ?>
      <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
      	<S:Body>
      		<ns2:download xmlns:ns2="http://server.binary.ws.codejava.net/">
      			<arg0>camera.png</arg0>
      		</ns2:download>
      	</S:Body>
      </S:Envelope>
       

    • Server Response:
      HTTP/1.1 200 OK
      Transfer-encoding: chunked
      Content-type: text/xml; charset=utf-8
      Date: Fri, 11 Oct 2013 02:48:45 GMT
      
      <?xml version="1.0" ?>
      <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
      	<S:Body>
      		<ns2:downloadResponse xmlns:ns2="http://server.binary.ws.codejava.net/">
      			<return>iVBORw0KGgoAAAANSUhEUgAAABAAA...</return>
      		</ns2:downloadResponse>
      	</S:Body>
      </S:Envelope>
       

CONCLUSION: As we mentioned earlier, this binary data transfer approach is only well-suited for working with small binary data because the base64 text encoding mechanism bloats data size greatly and slows down application performance.

 

Other Java Web Services Tutorial:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (WebServicesBinaryTransferExample.zip)WebServicesBinaryTransferExample.zip[Source codes and compile instructions]22 kB

Add comment

   


Comments 

#13Tabbarez2020-05-14 23:07
This example did not use encoding and decoding,

Only byte transfer...
Quote
#12victor2018-11-15 09:37
SOAP with attachment
Quote
#11Vinnie2018-04-27 15:51
This is a nice tutorial except for one thing: Where IS the WSDL???
Quote
#10chacaman2017-07-13 17:17
One question, i can gzip the byte array or compress?
Quote
#9swati2016-09-15 14:44
I need a program using JSON POST method uploading an
image in POSTMAN then it will call JSON webservices and that image has to store in new folder that file should be save as .png formate
Quote