jws

JAX-WS Dynamic Proxy Client Example

1. Introduction

Java API for XML Web Services (JAX-WS) is a Java programming language for creating web services, particularly SOAP services.

JAX-WS wsimport generates java stubs and binds the web service during the compile time. The generated client code binds to the WSDL at a specific service implementation. Clients need to regenerate the stubs when WSDL is updated.

JAX-WS provides libraries to construct services during run-time and invoke service’s operations via Dispatch interface. Dynamic web service clients don’t need to change when WSDL is updated.

In this example, I will demonstrate how to build a dynamic proxy web service client.

2. JAX-WS Server Application

Create a JAX-WS server application in three steps:

  • Create an Interface and annotate it with@WebService
  • Create an implementation class for the Interface
    and annotate it with @WebService(endpointInterface="")
  • Create an Endpoint to publish the service

Refer to my other article for step-by-step instructions.

This step will starts a server with two services: http://localhost:9980/bookSerer.wsdl and http://localhost:9990/mathSerer.wsdl.

http://localhost:9980/bookSerer.wsdl file content.

bookServer.wsdl

<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI (http://jax-ws.java.net). 
	RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e. --><!-- Generated by JAX-WS RI (http://jax-ws.java.net). 
	RI's version is JAX-WS RI 2.2.9-b130926.1035 svn-revision#5f6196f2b90e9460065a4c2f4e30e065b245e51e. -->
<definitions
	xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
	xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
	xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
	xmlns:tns="http://jcg.demo.zheng/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://jcg.demo.zheng/"
	name="BookServiceImplService">
	<types>
		<xsd:schema>
			<xsd:import namespace="http://jcg.demo.zheng/"
				schemaLocation="http://localhost:9980/bookServer?xsd=1"></xsd:import>
		</xsd:schema>
	</types>
	<message name="getBook">
		<part name="parameters" element="tns:getBook"></part>
	</message>
	<message name="getBookResponse">
		<part name="parameters" element="tns:getBookResponse"></part>
	</message>
	<portType name="BookService">
		<operation name="getBook">
			<input wsam:Action="http://jcg.demo.zheng/BookService/getBookRequest"
				message="tns:getBook"></input>
			<output wsam:Action="http://jcg.demo.zheng/BookService/getBookResponse"
				message="tns:getBookResponse"></output>
		</operation>
	</portType>
	<binding name="BookServiceImplPortBinding" type="tns:BookService">
		<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
			style="document"></soap:binding>
		<operation name="getBook">
			<soap:operation soapAction=""></soap:operation>
			<input>
				<soap:body use="literal"></soap:body>
			</input>
			<output>
				<soap:body use="literal"></soap:body>
			</output>
		</operation>
	</binding>
	<service name="BookServiceImplService">
		<port name="BookServiceImplPort" binding="tns:BookServiceImplPortBinding">
			<soap:address location="http://localhost:9980/bookServer"></soap:address>
		</port>
	</service>
</definitions>

3. Static Web Service Client

Build a static web service client with wsimport. This step creates two client applications: BookServiceClient and MathServiceClient.

Refer to my other article for step-by-step instructions.

4. Dynamic Proxy Web Service Client

There are three steps to build a dynamic proxy web client:

  1. Parse the web service WSDL into ServiceDetail data model
  2. Construct the Service via ServiceDetail
  3. Invoke the service’s operation via Dispatch method

4.1. Data Model

Create ServiceDetail class to track web service detail.

ServiceDetail.java

package jcg.demo.jaxws.client.model;

import java.util.List;

public class ServiceDetail {

	private String wsdl;

	private String nameSpace;
	private String prefix;
	private String serviceName;
	private String portName;

	private List operations;

	public ServiceDetail(String wsdl) {
		super();
		this.wsdl = wsdl;
	}

	public String getWsdl() {
		return wsdl;
	}

	public void setWsdl(String wsdl) {
		this.wsdl = wsdl;
	}

	public String getNameSpace() {
		return nameSpace;
	}

	public void setNameSpace(String nameSpace) {
		this.nameSpace = nameSpace;
	}

	public String getPrefix() {
		return prefix;
	}

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	public String getServiceName() {
		return serviceName;
	}

	public void setServiceName(String serviceName) {
		this.serviceName = serviceName;
	}

	public String getPortName() {
		return portName;
	}

	public void setPortName(String portName) {
		this.portName = portName;
	}

	public List getOperations() {
		return operations;
	}

	public void setOperations(List operations) {
		this.operations = operations;
	}
}

Create Operation class to track web service’s operation detail.

Operation.java

package jcg.demo.jaxws.client.model;

import java.util.List;

public class Operation {

	private String name;

	private List parameterNames;

	public Operation(String name) {
		super();
		this.name = name;
	}

	public Operation(String name, List parameterNames) {
		super();
		this.name = name;
		this.parameterNames = parameterNames;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List getParameterNames() {
		return parameterNames;
	}

	public void setParameterNames(List parameterNames) {
		this.parameterNames = parameterNames;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Operation other = (Operation) obj;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
}

4.2. Parse WSDL

Parse the WSDL by extracting the ServiceDetail out of the Document object.

4.2.1 ParseWsdlService

Create ParseWsdlService to parse WSDL into ServiceDetail

ParseWsdlService.java

package jcg.demo.jaxws.client;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import jcg.demo.jaxws.client.model.Operation;
import jcg.demo.jaxws.client.model.ServiceDetail;

public class ParseWsdlService {
	private static final String PORT = "port";
	private static final String SERVICE = "service";
	private static final String COMMENT = "#comment";
	private static final String TARGET_NAMESPACE = "targetNamespace";
	private static final String XML_SCHEMA_ATTR = "http://www.w3.org/2001/XMLSchema";
	private static final String OPERATION = "operation";
	private static final String OPERATION_1 = "wsdl:operation";

	public ServiceDetail parse(String wsdlPath)
			throws FileNotFoundException, SAXException, IOException, ParserConfigurationException {
		ServiceDetail sd = new ServiceDetail(wsdlPath);

		Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(readWsdl(wsdlPath));

		removeComments(document, document.getChildNodes());

		String tagPrefix = getNamespacePrefix(document);
		if (tagPrefix != null) {
			sd.setPrefix(tagPrefix);
		}

		String nameSpace = getTargetNamespace(document);
		sd.setNameSpace(nameSpace);

		List operations = getOperations(document);
		sd.setOperations(operations);

		String serviceName = getServiceName(document);
		sd.setServiceName(serviceName);

		String portName = getPortName(document);
		sd.setPortName(portName);
		return sd;
	}

	private String getServiceName(Document document) {
		String serviceName = null;
		if (document.getElementsByTagName(SERVICE).getLength() > 0) {
			NodeList nodeListOfService = document.getElementsByTagName(SERVICE);
			for (int i = 0; i  0) {
			NodeList nodeListOfService = document.getElementsByTagName(PORT);
			for (int i = 0; i < nodeListOfService.getLength(); i++) {
				Node portNode = nodeListOfService.item(i).getAttributes().getNamedItem("name");
				portName = portNode.getNodeValue();
			}
		}

		return portName;
	}

	private String getNamespacePrefix(Document document) {
		String tagPrefix = null;
		int l = document.getFirstChild().getAttributes().getLength();
		for (int i = 0; i < l; i++) {
			String cmpAttribute = document.getFirstChild().getAttributes().item(i).getNodeValue();
			if (cmpAttribute.equals(XML_SCHEMA_ATTR)) {
				tagPrefix = document.getFirstChild().getAttributes().item(i).getNodeName().replace("xmlns:", "");

			}
		}

		return tagPrefix;
	}

	private String getTargetNamespace(Document document) {
		return document.getFirstChild().getAttributes().getNamedItem(TARGET_NAMESPACE).getNodeValue();

	}

	private void removeComments(Document document, NodeList allNodesOfDocumnet) {
		for (int index = 0; index < allNodesOfDocumnet.getLength(); index++) {
			if (document.getFirstChild().getNodeName().equalsIgnoreCase(COMMENT)) {
				document.removeChild(document.getFirstChild());
			}
		}
	}

	private List getOperations(Document document) {
		List operations = new ArrayList();

		NodeList nodeListOfOperations = null;
		if ((document.getElementsByTagName(OPERATION).getLength() > 0)
				|| (document.getElementsByTagName(OPERATION_1).getLength() > 0)) {

			if (document.getElementsByTagName(OPERATION).getLength() > 0) {
				nodeListOfOperations = document.getElementsByTagName(OPERATION);
			} else if (document.getElementsByTagName(OPERATION_1).getLength() > 0) {
				nodeListOfOperations = document.getElementsByTagName(OPERATION_1);
			}

		}

		for (int i = 0; i < nodeListOfOperations.getLength(); i++) {
			Operation ope = new Operation(
					nodeListOfOperations.item(i).getAttributes().getNamedItem("name").getNodeValue());
			Node paraOrder = nodeListOfOperations.item(i).getAttributes().getNamedItem("parameterOrder");
			if (paraOrder != null) {
				ope.setParameterNames(Arrays.asList(paraOrder.getNodeValue().split(" ")));
			} else {
				ope.setParameterNames(Arrays.asList("number".split(",")));
			}
			if (!operations.contains(ope)) {
				operations.add(ope);
			}
		}

		return operations;
	}

	private InputStream readWsdl(String wsdlUrl) throws IOException {
		URL url = new URL(wsdlUrl);
		URLConnection uc = url.openConnection();
		return uc.getInputStream();
	}
}

Note: The parsing logic is based on Document structure.

4.2.2 ParseWsdlServiceTest

Create ParseWsdlServiceTest to test the parsing logic.

ParseWsdlServiceTest.java

package jcg.demo.jaxws.client;

import static org.junit.Assert.assertEquals;

import java.io.FileNotFoundException;
import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import org.junit.Test;
import org.xml.sax.SAXException;

import jcg.demo.jaxws.client.model.ServiceDetail;

public class ParseWsdlServiceTest {

	private ParseWsdlService parser = new ParseWsdlService();

	@Test
	public void parse_mathService()
			throws FileNotFoundException, SAXException, IOException, ParserConfigurationException {
		String wsdlPath = "http://localhost:9990/mathServer?wsdl";

		ServiceDetail mathService = parser.parse(wsdlPath);

		assertEquals("http://jcg.demo.mary/", mathService.getNameSpace());
		assertEquals("MathServiceImplService", mathService.getServiceName());
		assertEquals("MathServiceImplPort", mathService.getPortName());
		assertEquals(2, mathService.getOperations().size());
		assertEquals("sum", mathService.getOperations().get(0).getName());
		assertEquals("isPrimeNumber", mathService.getOperations().get(1).getName());

	}

	@Test
	public void parse_bookService()
			throws FileNotFoundException, SAXException, IOException, ParserConfigurationException {
		String wsdlPath = "http://localhost:9980/bookServer?wsdl";

		ServiceDetail bookService = parser.parse(wsdlPath);

		assertEquals("http://jcg.demo.zheng/", bookService.getNameSpace());
		assertEquals("BookServiceImplService", bookService.getServiceName());
		assertEquals("BookServiceImplPort", bookService.getPortName());
		assertEquals(1, bookService.getOperations().size());
		assertEquals("getBook", bookService.getOperations().get(0).getName());
	}
}

Note: The parsing logic is tested based on two clients only.

4.3. Build Dynamic Proxy Client

Construct Service from ServiceDetail and create invokeOperation via Dispatch inteface.

4.3.1. DynamicWebServiceClient

Create DynamicWebServiceClient.

DynamicWebServiceClient.java

package jcg.demo.jaxws.client;

import java.io.IOException;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;

import jcg.demo.jaxws.client.model.Operation;
import jcg.demo.jaxws.client.model.ServiceDetail;

public class DynamicWebServiceClient {

	public SOAPMessage invokeOperation(ServiceDetail serviceDetail, String operationName, List args)
			throws SOAPException, IOException {

		QName serviceQN = new QName(serviceDetail.getNameSpace(), serviceDetail.getServiceName());
		QName portQN = new QName(serviceDetail.getNameSpace(), serviceDetail.getPortName());

		Service service = Service.create(serviceQN);
		service.addPort(portQN, SOAPBinding.SOAP11HTTP_BINDING, serviceDetail.getWsdl());

		Operation foundOp = foundOperation(serviceDetail, operationName);
		if (foundOp == null) {
			throw new RuntimeException(serviceDetail.getWsdl() + " Not support operation: " + operationName);
		}

		Dispatch dispatcher = service.createDispatch(portQN, SOAPMessage.class, Service.Mode.MESSAGE);

		dispatcher.getRequestContext().put(Dispatch.USERNAME_PROPERTY, "mzheng");
		dispatcher.getRequestContext().put(Dispatch.PASSWORD_PROPERTY, "great");

		MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
		SOAPMessage request = mf.createMessage();

		SOAPPart part = request.getSOAPPart();

		SOAPEnvelope env = part.getEnvelope();
		env.addNamespaceDeclaration(serviceDetail.getPrefix(), serviceDetail.getNameSpace());

		SOAPBody body = env.getBody();
		SOAPElement operation = body.addChildElement(operationName, serviceDetail.getPrefix());
		int argrIndex = 0;
		for (String arg : foundOp.getParameterNames()) {
			SOAPElement value = operation.addChildElement(arg);
			value.addTextNode(args.get(argrIndex));
			argrIndex++;
		}
		request.saveChanges();
		System.out.println("Request: " + SoapMessageUtil.outputSoapMessage(request));
		return dispatcher.invoke(request);

	}

	private Operation foundOperation(ServiceDetail serviceDetail, String operationName) {
		Operation operation = serviceDetail.getOperations().stream().filter(e -> e.getName().equals(operationName))
				.findFirst().orElse(null);

		return operation != null ? operation : null;
	}

}

4.3.2. DynamicWebServiceClientTest

Create DynamicWebServiceClientTest to test

DynamicWebServiceClientTest.java

package jcg.demo.jaxws.client;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.xml.soap.SOAPMessage;

import org.junit.Test;

import jcg.demo.jaxws.client.model.Operation;
import jcg.demo.jaxws.client.model.ServiceDetail;

public class DynamicWebServiceClientTest {

	private DynamicWebServiceClient webServiceClient = new DynamicWebServiceClient();

	@Test
	public void invoke_mathService_isPrimeNumber_happyPath() {

		ServiceDetail wsdlInfor = setMathServiceDetail();

		try {
			SOAPMessage response = webServiceClient.invokeOperation(wsdlInfor, "isPrimeNumber",
					Arrays.asList("5".split(",")));
			assertNotNull(response);
			String ret = SoapMessageUtil.outputSoapMessage(response);
			assertTrue(ret.contains("true"));

		} catch (Exception e) {
			System.out.println("Error " + e.getMessage());
		}
	}

	@Test
	public void invoke_mathService_sum_happyPath() {

		ServiceDetail wsdlInfor = setMathServiceDetail();

		try {
			SOAPMessage response = webServiceClient.invokeOperation(wsdlInfor, "sum", Arrays.asList("4,5".split(",")));
			assertNotNull(response);
			String ret = SoapMessageUtil.outputSoapMessage(response);
			assertTrue(ret.contains("9"));

		} catch (Exception e) {
			System.out.println("Error " + e.getMessage());
		}

	}

	private ServiceDetail setMathServiceDetail() {
		ServiceDetail wsdlInfor = new ServiceDetail("http://localhost:9990/mathServer?wsdl");
		wsdlInfor.setNameSpace("http://jcg.demo.mary/");
		List operations = new ArrayList();
		operations.add(new Operation("isPrimeNumber", Arrays.asList("number".split(","))));
		operations.add(new Operation("sum", Arrays.asList("int_a,int_b".split(","))));
		wsdlInfor.setOperations(operations);
		wsdlInfor.setPortName("MathServiceImplPort");
		wsdlInfor.setPrefix("jcg");
		wsdlInfor.setServiceName("MathServiceImplService");
		return wsdlInfor;
	}
}

4.4. Create Dynamic Web Service Application

Create a dynamic web service application by parsing the web service WSDL and then build the service with the service detail.

ClientApp.java

package jcg.demo.jaxws.client;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;

import org.xml.sax.SAXException;

import jcg.demo.jaxws.client.model.ServiceDetail;

public class ClientApp {

	public static void main(String[] args) {
		DynamicWebServiceClient dynamicClient = new DynamicWebServiceClient();

		ParseWsdlService parseService = new ParseWsdlService();

		try {
			mathClient_sum(dynamicClient, parseService);
			mathClient_isPrimeNumber(dynamicClient, parseService);
			bookClient(dynamicClient, parseService);
		} catch (SOAPException | SAXException | IOException | ParserConfigurationException e) {
			e.printStackTrace();
		}
	}

	private static void mathClient_sum(DynamicWebServiceClient dynamicClient, ParseWsdlService parseService)
			throws FileNotFoundException, SAXException, IOException, ParserConfigurationException, SOAPException {

		ServiceDetail mathService = parseService.parse("http://localhost:9990/mathServer?wsdl");

		Instant start = Instant.now();
		SOAPMessage response = dynamicClient.invokeOperation(mathService, "sum", Arrays.asList("4,5".split(",")));
		Instant end = Instant.now();
		System.out.println("Response: " + SoapMessageUtil.outputSoapMessage(response));
		System.out.println("math_dynamicClient_sum, took " + Duration.between(start, end));

	}

	private static void mathClient_isPrimeNumber(DynamicWebServiceClient dynamicClient, ParseWsdlService parseService)
			throws FileNotFoundException, SAXException, IOException, ParserConfigurationException, SOAPException {

		ServiceDetail mathService = parseService.parse("http://localhost:9990/mathServer?wsdl");

		Instant start = Instant.now();
		SOAPMessage response = dynamicClient.invokeOperation(mathService, "isPrimeNumber",
				Arrays.asList("45".split(",")));
		Instant end = Instant.now();
		System.out.println("Response: " + SoapMessageUtil.outputSoapMessage(response));
		System.out.println("math_dynamicClient_isPrimeNumber, took " + Duration.between(start, end));

	}

	private static void bookClient(DynamicWebServiceClient dynamicClient, ParseWsdlService parseService)
			throws FileNotFoundException, SAXException, IOException, ParserConfigurationException, SOAPException {

		ServiceDetail service = parseService.parse("http://localhost:9980/bookServer?wsdl");

		for (int i = 1; i < 6; i++) {
			Instant start = Instant.now();
			SOAPMessage response = dynamicClient.invokeOperation(service, "getBook",
					Arrays.asList(String.valueOf(i).split(",")));

			Instant end = Instant.now();
			System.out.println("Response: " + SoapMessageUtil.outputSoapMessage(response));
			System.out.println("book_dynamicClient_getBook, took " + Duration.between(start, end));

		}
	}
}

Image shows both jax-ws-client-dynamic and jax-ws-client-static structure.

Figure 1: Jax-ws Clients

5. Demo Time

Start ServerApp which includes both MathService and BookService.

Start BookServiceClient from jax-ws-client-staticand capture the output:

BookServiceClient output

Mary Book
book_staticClient_getBook, took PT0.036S
Terry Book 
book_staticClient_getBook, took PT0.006S
Ben Best Book
book_staticClient_getBook, took PT0.005S
Alex Life
book_staticClient_getBook, took PT0.005S
David Music
book_staticClient_getBook, took PT0.004S

Start MathServiceClient from jax-ws-client-staticand capture the output:

MathServiceClient output

100003 is prime number. 
math_staticClient_isPrimeNumber, took PT0.004S
100019 is prime number. 
math_staticClient_isPrimeNumber, took PT0.004S
100043 is prime number. 
math_staticClient_isPrimeNumber, took PT0.005S
100049 is prime number. 
math_staticClient_isPrimeNumber, took PT0.004S
100057 is prime number. 
math_staticClient_isPrimeNumber, took PT0.004S
100069 is prime number. 
math_staticClient_isPrimeNumber, took PT0.004S

Start ClientApp from jax-ws-client-dynamic and capture the output:

ClientApp output

Request: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://jcg.demo.mary/"><SOAP-ENV:Header/><SOAP-ENV:Body><xsd:sum><int_a>4</int_a><int_b>5</int_b></xsd:sum></SOAP-ENV:Body></SOAP-ENV:Envelope>
Response: <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:sumResponse xmlns:ns2="http://jcg.demo.mary/"><return>9</return></ns2:sumResponse></S:Body></S:Envelope>
math_dynamicClient_sum, took PT0.484S
Request: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://jcg.demo.mary/"><SOAP-ENV:Header/><SOAP-ENV:Body><xsd:isPrimeNumber><number>45</number></xsd:isPrimeNumber></SOAP-ENV:Body></SOAP-ENV:Envelope>
Response: <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:isPrimeNumberResponse xmlns:ns2="http://jcg.demo.mary/"><return>false</return></ns2:isPrimeNumberResponse></S:Body></S:Envelope>
math_dynamicClient_isPrimeNumber, took PT0.05S
Request: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://jcg.demo.zheng/"><SOAP-ENV:Header/><SOAP-ENV:Body><xsd:getBook><number>1</number></xsd:getBook></SOAP-ENV:Body></SOAP-ENV:Envelope>
Response: <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://jcg.demo.zheng/"><return><id>1</id><name>Mary Book</name></return></ns2:getBookResponse></S:Body></S:Envelope>
book_dynamicClient_getBook, took PT0.057S
Request: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://jcg.demo.zheng/"><SOAP-ENV:Header/><SOAP-ENV:Body><xsd:getBook><number>2</number></xsd:getBook></SOAP-ENV:Body></SOAP-ENV:Envelope>
Response: <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://jcg.demo.zheng/"><return><id>2</id><name>Terry Book </name></return></ns2:getBookResponse></S:Body></S:Envelope>
book_dynamicClient_getBook, took PT0.055S
Request: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://jcg.demo.zheng/"><SOAP-ENV:Header/><SOAP-ENV:Body><xsd:getBook><number>3</number></xsd:getBook></SOAP-ENV:Body></SOAP-ENV:Envelope>
Response: <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://jcg.demo.zheng/"><return><id>3</id><name>Ben Best Book</name></return></ns2:getBookResponse></S:Body></S:Envelope>
book_dynamicClient_getBook, took PT0.036S
Request: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://jcg.demo.zheng/"><SOAP-ENV:Header/><SOAP-ENV:Body><xsd:getBook><number>4</number></xsd:getBook></SOAP-ENV:Body></SOAP-ENV:Envelope>
Response: <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://jcg.demo.zheng/"><return><id>4</id><name>Alex Life</name></return></ns2:getBookResponse></S:Body></S:Envelope>
book_dynamicClient_getBook, took PT0.034S
Request: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://jcg.demo.zheng/"><SOAP-ENV:Header/><SOAP-ENV:Body><xsd:getBook><number>5</number></xsd:getBook></SOAP-ENV:Body></SOAP-ENV:Envelope>
Response: <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/><S:Body><ns2:getBookResponse xmlns:ns2="http://jcg.demo.zheng/"><return><id>5</id><name>David Music</name></return></ns2:getBookResponse></S:Body></S:Envelope>
book_dynamicClient_getBook, took PT0.031S

Note: Static web service client is 25ms faster than the dynamic web service client for the same operation.

5.1 Update JAX-WS Server and Demo Again

Stop ServerAppand change the MathService interface and then repeat the steps above.

The MathServiceClient caught exception because the generated stub is out of sync with service implementation, but the dynamic web service client ClientApp still works as expected.

6. Summary

In this example, I built two simple JAX-WS services and static and dynamic web service client with JDK libraries only. Other vendors, such as Apache CXF, provides JAxWsProxyFactoryBean to achieve the same goal.

The dynamic web service client is a little slower than the static web service, but provides greater flexibility.

Click here for the JAX-WS client solutions comparison.

7. Download the Source Code

This example consists of a JAX-WS server, a static web service client and a dynamic web service client.

Download
You can download the full source code of this example here:JAX-WS Dynamic Proxy Client Example

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Aquiles Bailo
Aquiles Bailo
4 years ago

A couple details:

1. You forgot to show the SoapMessageUtil.java code here, however it’s included inside the JAX-WS-Demo.zip linked at the bottom of the article.
2. When copying from your IDE to web, parameterized types between > and < symbols, are not shown, for those copying from web to IDE instead of using the pack.

Cheers!

Neelam
Neelam
3 years ago

I tried executing the code but I am getting SOAP Fault – com.sun.xml.internal.ws.fault.ServerSOAPFaultException: Client received SOAP Fault from server: Cannot find dispatch method for {http://impl.service.jaxws.demo.jcg/}sum Please see the server log to find more detail regarding exact cause of the failure.

What can be the reason for this? I am not able to run the code. Please solve.

Back to top button