Creating a SOAP web service with Spring Boot

Creating a SOAP web service with Spring Boot

Creating a SOAP web service with Spring Boot

Main Application Spring Boot File:

[java]

package com.ngdeveloper;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CouponApplication {

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

[/java]

pom.xml file:

This below pom.xml file contains the plugin to generate the output directory files from the xsd file, so create the pom.xml, xsd file, endpoints then by starting your spring boot application you will be able to find the other required files generated.

These are the files will be generated automatically with this heading info,

[plain]

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.7
// See <a href=”http://java.sun.com/xml/jaxb”>http://java.sun.com/xml/jaxb</a>
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2019.01.23 at 03:41:28 PM IST
//

[/plain]

  • CouponDetails
  • GetCouponDetailsRequest
  • GetCouponDetailsResponse
  • ObjectFactory
  • package-info

[xml]

<?xml version=”1.0″ encoding=”UTF-8″?>
<project xmlns=”http://maven.apache.org/POM/4.0.0″
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd”>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath /> <!– lookup parent from repository –>
</parent>
<groupId>com.ngdeveloper</groupId>
<artifactId>Coupon</artifactId>
<version>1.0</version>
<name>Coupon</name>
<description>Coupon Web service</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>
</plugins>
</build>

</project>

[/xml]

Create a xsd file for your request and responses,

This below coupon-details.xsd file is the request and response file,

[xml]

<xs:schema xmlns:xs=”http://www.w3.org/2001/XMLSchema” xmlns:tns=”http://ngdeveloper.com/coupon”
targetNamespace=”http://ngdeveloper.com/coupon” elementFormDefault=”qualified”>

<xs:element name=”GetCouponDetailsRequest”>
<xs:complexType>
<xs:sequence>
<xs:element name=”id” type=”xs:int” />
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:element name=”GetCouponDetailsResponse”>
<xs:complexType>
<xs:sequence>
<xs:element name=”CouponDetails” type=”tns:CouponDetails” />
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:complexType name=”CouponDetails”>
<xs:sequence>
<xs:element name=”id” type=”xs:int” />
<xs:element name=”title” type=”xs:string” />
<xs:element name=”code” type=”xs:string” />
</xs:sequence>
</xs:complexType>

</xs:schema>

[/xml]

Creating an endpoint:

[java]

package com.ngdeveloper.ws.endpoints;

import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

import com.ngdeveloper.CouponDetails;
import com.ngdeveloper.GetCouponDetailsRequest;
import com.ngdeveloper.GetCouponDetailsResponse;

@Endpoint
public class CouponDetailsEndPoint {

@PayloadRoot(namespace = “http://ngdeveloper.com/coupon”, localPart = “GetCouponDetailsRequest”)
@ResponsePayload
public GetCouponDetailsResponse processCouponDetailsRequest(@RequestPayload GetCouponDetailsRequest request) {
GetCouponDetailsResponse response = new GetCouponDetailsResponse();
CouponDetails couponDetails = new CouponDetails();
couponDetails.setId(request.getId());
couponDetails.setTitle(“10% OFF on Paytm”);
couponDetails.setCode(“PYTM10”);
response.setCouponDetails(couponDetails);
return response;
}
}

[/java]

WebserviceConfig file:

This is the configuration file in spring boot for soap webservice and load the xsd file.

[java]

package com.ngdeveloper;

import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, “/ws/*”);
}

@Bean(name = “coupon”)
public DefaultWsdl11Definition defaultCouponWsdl11Definition(XsdSchema couponSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName(“CouponPort”);
wsdl11Definition.setLocationUri(“/ws”);
wsdl11Definition.setTargetNamespace(“http://ngdeveloper.com/coupon”);
wsdl11Definition.setSchema(couponSchema);
return wsdl11Definition;
}

@Bean
public XsdSchema couponSchema() {
return new SimpleXsdSchema(new ClassPathResource(“coupon-details.xsd”));
}
}

[/java]

Add these below lines in application.properties to log both input request and output response,

logging.level.org.springframework.web=DEBUG
logging.level.org.springframework.ws.client.MessageTracing.sent=DEBUG
logging.level.org.springframework.ws.server.MessageTracing.sent=DEBUG
logging.level.org.springframework.ws.client.MessageTracing.received=TRACE
logging.level.org.springframework.ws.server.MessageTracing.received=TRACE

Testing created SOAP web service:

Install wizdler plugin to test SOAP web services directly from your chrome browser.

You can also use SOAP UI tool (both free and pro tools available here)

Open your wsdl link in chrome browser then click wizdler icon to pass the request.

How to generate java classes from xsd:

This below plugin is going to help to generate java classes from xsd file.

Add the below plugin to your pom,xml,
[xml]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
<outputDirectory>${project.basedir}/src/main/java/</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>
[/xml]

Note: If you have this plugin also, then it may not work, in that case comment the below section till to generate the class files from the xsd resources.

[xml]
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.14.0</version>
[/xml]

Run

mvn jaxb2:xjc

(or)

jaxb2:xjc (if you are running from eclipse)

to generate the java classes from xsd schema.

 

WSImport tool to generate classes from WSDL:

wsimport -keep -s F:\some_folder http://ngdeveloper.com/test?wsdl

This above command parses the WSDL and generates the classes from the WSDL.

 

Getting any error something like this,

[plain]

parsing WSDL…

[ERROR] A class/interface with the same name

[/plain]

 

Then you can try with the below commands,

wsimport -keep -p F:\some_folder http://ngdeveloper.com/test?wsdl -B-XautoNameResolution

 

WSImport tool to generate classes with your own package defined from WSDL:

wsimport -keep -s F:\some_folder http://ngdeveloper.com/test?wsdl -p com.ngdeveloper

 

This one generates all the clients with the package as com.ngdeveloper instead of the default one.

 

Still facing the issue ?

 

This error occurs if you have same class names under the same package with different cases like, ngDeveloper and NGDeveloper, so directly change the wsdl and run wsimport tool.

Below wsimport command runs with -p (package names)

wsimport -keep -s D:\path_to_Generate D:\YOUR_WSDL.wsdl -B-XautoNameResolution -p com.ngdeveloper.beans

 

Here -p takes the package name,

.wsdl loaded from local path and classes will be generated in path_to_generate folder mentioned above.

 

If you want to generate the same through maven then add the below entry in your pom.xml,

[code language=”xml”]

<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.14.0</version>
<executions>
<execution>
<id>myclientservice</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<generatePackage>com.ngdeveloper.myclientservice.beans</generatePackage>
<generateDirectory>${project.basedir}/src/main/java</generateDirectory>
<schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
<schemaIncludes>
<include>myWsdl.wsdl</include>
</schemaIncludes>
<removeOldOutput>false</removeOldOutput>
<forceRegenerate>false</forceRegenerate>
<args>
<arg>-XautoNameResolution</arg>
<arg>-no-header</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>

[/code]

 

Generally wsimport tool can be used to consume the wsdl and the maven xjc way can be used to clone the existing wsdl and create similar to it.

 

Steps to Clone WSDL / Generating xsd from the WSDL’s:

Do you want to clone the wsdl ? / Do you want to generate the xsd from the wsdl and create the classes from xsd to create your own publisher soap wsdl ?

Then these are the steps:

  1. Import your wsdl in SOAP.
  2. Right click on the imported wsdl and click “Show interface viewer”
  3. Click on “WSDL Content” tab
  4. Click on “schemas” (available in the left sidebar, to see all the xsd’s present in the wsdl)
  5. You will also have the option to export all the wsdl xsd’s to outside of soap (WSDL Content tab > Exports the entire wsdl sub menu)

 

Now it’s time to create a single xsd with all the xsd’s you need from the above exported xsd’s list then java client codes can be generated from the single xsd.

Then create an endpoint with request and response, finally publish your own cloned soap producer wsdl.

 

Common Errors & Resolutions:

Error loading [http://localhost:8443/ngdeveloper-soap/api/ws/GetCoupons.xsd]: org.apache.xmlbeans.XmlException: org.apache.xmlbeans.XmlException: error: Unexpected end of file after nul

This error generally means that GetCoupons.xsd is not loading, you should try to open up this link (http://localhost:8443/ngdeveloper-soap/api/ws/GetCoupons.xsd) in browser and it must be visible and show the contents of getcoupons.xsd file

If you are not able to see the contents/throwing any error then you must need to check

<xsd:include schemaLocation=”GetCoupons.xsd”/> [this much work]

<xsd:import namespace=”http://ngdeveloper.com” schemaLocation=”GetCoupons.xsd”/>

 

 

 

 

Happy coding!

Leave a Reply