Enterprise Java

Writing and Consuming SOAP Webservice with Spring

In the era of RESTful Web Services, I got a chance to consume SOAP Web Service. To do the same I chosen Spring, reason being we are already using Spring as backend framework in our project and secondly it provides an intuitive way to interact service(s) with well-defined boundaries to promote reusability and portability through WebServiceTemplate.

Assuming you already know about SOAP Web Services, let’s start creating hello-world soap service running on port 9999 and client to consume the same, following below steps:

Step 1: Go to start.spring.io and create a new project soap-server adding the Web starters, based on the following image:

soap-server

Step 2: Edit SoapServerApplication.java to publish the hello-world service at Endpoint – http://localhost:9999/service/hello-world, as follows:

package com.arpit.soap.server.main;

import javax.xml.ws.Endpoint;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.arpit.soap.server.service.impl.HelloWorldServiceImpl;

@SpringBootApplication
public class SoapServerApplication implements CommandLineRunner {

	@Value("${service.port}")
	private String servicePort;

	@Override
	public void run(String... args) throws Exception {
		Endpoint.publish("http://localhost:" + servicePort
				+ "/service/hello-world", new HelloWorldServiceImpl());
	}

	public static void main(String[] args) {
		SpringApplication.run(SoapServerApplication.class, args);
	}
}

Step 3: Edit application.properties to specify the application name, port and port number of hello-world service, as follows:

server.port=9000
spring.application.name=soap-server

## Soap Service Port
service.port=9999

Step 4: Create additional packages as com.arpit.soap.server.service and com.arpit.soap.server.service.impl to define the Web Service and it’s implementation, as follows:

HelloWorldService.java

package com.arpit.soap.server.service;

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

import com.arpit.soap.server.model.ApplicationCredentials;

@WebService
public interface HelloWorldService {

	@WebMethod(operationName = "helloWorld", action = "https://aggarwalarpit.wordpress.com/hello-world/helloWorld")
	String helloWorld(final String name,
			@WebParam(header = true) final ApplicationCredentials credential);

}

@WebService specified above marks a Java class as implementing a Web Service, or a Java interface as defining a Web Service interface.

@WebMethod specified above marks a Java method as a Web Service operation.

@WebParam specified above customize the mapping of an individual parameter to a Web Service message part and XML element.

HelloWorldServiceImpl.java

package com.arpit.soap.server.service.impl;

import javax.jws.WebService;

import com.arpit.soap.server.model.ApplicationCredentials;
import com.arpit.soap.server.service.HelloWorldService;

@WebService(endpointInterface = "com.arpit.soap.server.service.HelloWorldService")
public class HelloWorldServiceImpl implements HelloWorldService {

	@Override
	public String helloWorld(final String name,
			final ApplicationCredentials credential) {
		return "Hello World from " + name;
	}
}

Step 5: Move to soap-server directory and run command: mvn spring-boot:run. Once running, open http://localhost:9999/service/hello-world?wsdl to view the WSDL for the hello-world service.

Next, we will create soap-client which will consume our newly created hello-world service.

Step 6: Go to start.spring.io and create a new project soap-client adding the Web, Web Services starters, based on the following image:

soap-client

Step 7: Edit SoapClientApplication.java to create a request to hello-world web service, sending the same to soap-server along with header and get the response from it, as follows:

package com.arpit.soap.client.main;

import java.io.IOException;
import java.io.StringWriter;

import javax.xml.bind.JAXBElement;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.xml.transform.StringSource;

import com.arpit.soap.server.service.ApplicationCredentials;
import com.arpit.soap.server.service.HelloWorld;
import com.arpit.soap.server.service.HelloWorldResponse;
import com.arpit.soap.server.service.ObjectFactory;

@SpringBootApplication
@ComponentScan("com.arpit.soap.client.config")
public class SoapClientApplication implements CommandLineRunner {

	@Autowired
	@Qualifier("webServiceTemplate")
	private WebServiceTemplate webServiceTemplate;

	@Value("#{'${service.soap.action}'}")
	private String serviceSoapAction;

	@Value("#{'${service.user.id}'}")
	private String serviceUserId;

	@Value("#{'${service.user.password}'}")
	private String serviceUserPassword;

	public static void main(String[] args) {
		SpringApplication.run(SoapClientApplication.class, args);
		System.exit(0);
	}

	public void run(String... args) throws Exception {
		final HelloWorld helloWorld = createHelloWorldRequest();
		@SuppressWarnings("unchecked")
		final JAXBElement<HelloWorldResponse> jaxbElement = (JAXBElement<HelloWorldResponse>) sendAndRecieve(helloWorld);
		final HelloWorldResponse helloWorldResponse = jaxbElement.getValue();
		System.out.println(helloWorldResponse.getReturn());
	}

	private Object sendAndRecieve(HelloWorld seatMapRequestType) {
		return webServiceTemplate.marshalSendAndReceive(seatMapRequestType,
				new WebServiceMessageCallback() {
					public void doWithMessage(WebServiceMessage message)
							throws IOException, TransformerException {
						SoapMessage soapMessage = (SoapMessage) message;
						soapMessage.setSoapAction(serviceSoapAction);
						org.springframework.ws.soap.SoapHeader soapheader = soapMessage
								.getSoapHeader();
						final StringWriter out = new StringWriter();
						webServiceTemplate.getMarshaller().marshal(
								getHeader(serviceUserId, serviceUserPassword),
								new StreamResult(out));
						Transformer transformer = TransformerFactory
								.newInstance().newTransformer();
						transformer.transform(new StringSource(out.toString()),
								soapheader.getResult());
					}
				});
	}

	private Object getHeader(final String userId, final String password) {
		final https.aggarwalarpit_wordpress.ObjectFactory headerObjectFactory = new https.aggarwalarpit_wordpress.ObjectFactory();
		final ApplicationCredentials applicationCredentials = new ApplicationCredentials();
		applicationCredentials.setUserId(userId);
		applicationCredentials.setPassword(password);
		final JAXBElement<ApplicationCredentials> header = headerObjectFactory
				.createApplicationCredentials(applicationCredentials);
		return header;
	}

	private HelloWorld createHelloWorldRequest() {
		final ObjectFactory objectFactory = new ObjectFactory();
		final HelloWorld helloWorld = objectFactory.createHelloWorld();
		helloWorld.setArg0("Arpit");
		return helloWorld;
	}

}

Step 8: Next, create additional package com.arpit.soap.client.config to configure WebServiceTemplate, as follows:

ApplicationConfig.java

package com.arpit.soap.client.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
@EnableWebMvc
public class ApplicationConfig extends WebMvcConfigurerAdapter {

	@Value("#{'${service.endpoint}'}")
	private String serviceEndpoint;

	@Value("#{'${marshaller.packages.to.scan}'}")
	private String marshallerPackagesToScan;

	@Value("#{'${unmarshaller.packages.to.scan}'}")
	private String unmarshallerPackagesToScan;

	@Bean
	public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}

	@Bean
	public SaajSoapMessageFactory messageFactory() {
		SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory();
		messageFactory.afterPropertiesSet();
		return messageFactory;
	}

	@Bean
	public Jaxb2Marshaller marshaller() {
		Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
		marshaller.setPackagesToScan(marshallerPackagesToScan.split(","));
		return marshaller;
	}

	@Bean
	public Jaxb2Marshaller unmarshaller() {
		Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
		unmarshaller.setPackagesToScan(unmarshallerPackagesToScan.split(","));
		return unmarshaller;
	}

	@Bean
	public WebServiceTemplate webServiceTemplate() {
		WebServiceTemplate webServiceTemplate = new WebServiceTemplate(
				messageFactory());
		webServiceTemplate.setMarshaller(marshaller());
		webServiceTemplate.setUnmarshaller(unmarshaller());
		webServiceTemplate.setMessageSender(messageSender());
		webServiceTemplate.setDefaultUri(serviceEndpoint);
		return webServiceTemplate;
	}

	@Bean
	public HttpComponentsMessageSender messageSender() {
		HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
		return httpComponentsMessageSender;
	}
}

Step 9: Edit application.properties to specify the application name, port and hello-world soap web service configurations, as follows:

server.port=9000
spring.application.name=soap-client

## Soap Service Configuration

service.endpoint=http://localhost:9999/service/hello-world
service.soap.action=https://aggarwalarpit.wordpress.com/hello-world/helloWorld
service.user.id=arpit
service.user.password=arpit
marshaller.packages.to.scan=com.arpit.soap.server.service
unmarshaller.packages.to.scan=com.arpit.soap.server.service

service.endpoint specified above is the URL provided to the service user to invoke the services exposed by the service provider.

service.soap.action specifies which process or program that need to be called when a request is sent by the service requester and also defines the relative path of the process/program.

marshaller.packages.to.scan specifies the packages to scan at time of marshalling before sending the request to the server.

unmarshaller.packages.to.scan specifies the packages to scan at time of unmarshalling after receiving the request from the server.

Now, we will generate Java Objects from WSDL using wsimport and copy it to the soap-client project executing below command on the terminal:

wsimport -keep -verbose http://localhost:9999/service/hello-world?wsdl

Step 10: Move to soap-client directory and run command: mvn spring-boot:run. Once command finishes we will see “Hello World from Arpit” as response from hello-world soap service on console.

While running if you are getting error as – Unable to marshal type “com.arpit.soap.server.service.HelloWorld” as an element because it is missing an @XmlRootElement annotation then add @XmlRootElement(name = “helloWorld”, namespace = “http://service.server.soap.arpit.com/ “) to the com.arpit.soap.server.service.HelloWorld, where namespace should be matched from xmlns:ser defined in soap envelope, as below:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.server.soap.arpit.com/">
   <soapenv:Header>
      <ser:arg1>
         <userId>arpit</userId>
         <password>arpit</password>
      </ser:arg1>
   </soapenv:Header>
   <soapenv:Body>
      <ser:helloWorld>
         <!--Optional:-->
         <arg0>Arpit</arg0>
      </ser:helloWorld>
   </soapenv:Body>
</soapenv:Envelope>

The complete source code is hosted on github.

Reference: Writing and Consuming SOAP Webservice with Spring from our JCG partner Arpit Aggarwal at the Arpit Aggarwal blog.

Arpit Aggarwal

Arpit is a Consultant at Xebia India. He has been designing and building J2EE applications since more than 6 years. He is fond of Object Oriented and lover of Functional programming. You can read more of his writings at aggarwalarpit.wordpress.com
Subscribe
Notify of
guest

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

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Antara
Antara
7 years ago

how the wsld file is getting created not able to understand need to do same thing as done above using gradle

Aryasindhu Sahu
7 years ago

Class com.arpit.soap.server.model.ApplicationCredentials is missing in the document.
Please refer to this link for the same : https://github.com/arpitaggarwal/soap/blob/master/soap-server/src/main/java/com/arpit/soap/server/model/ApplicationCredentials.java

Carlos Latanza
Carlos Latanza
7 years ago

Hi, i have created a Soap service using your blog as reference but spring autowire is not working when i try to inject a service on webservice class, i tried to use @Service on webservice class, extends SpringBeanAutowiringSupport but its still not working. Can you help me with that please?

sravya
sravya
3 years ago
Reply to  Carlos Latanza

I am facing same issue as well. Can any one suggest solution to this. My guess: Since we are using new keyword, autowired classes are null.

Muhammad
6 years ago

well its workable for me . Thanks.

Anurag Benjwal
Anurag Benjwal
6 years ago

Hi arpit,
I have to received the soap packet as a request on my Controller and further parse them. So would you please provide me some hint to get this done.

Back to top button