Embracing the Messiness in Search of Epic Solutions

Using Spring Web Services and JAXB to Invoke Web Service Based on WSDL

Posted

in

There are several ways to consume a web service based on a WSDL from Java. After trying a couple of approaches, I’m currently leaning towards Spring Web Services and JAXB. The biggest advantage of using both Spring Web Services and JAXB to consume a web service is the flexibility to change the web service URL without the need to regenerate the needed Java files, especially if you have a different web service URL for each environment (DEV, TEST and PROD).

In this tutorial, I’m going to consume this freely available web service that allows me to convert the currency rate from one country to another: http://www.webservicex.net/CurrencyConvertor.asmx?WSDL

currency.wsdl ( src/main/resources )

The first step is to open the WSDL link on the browser and save a copy of it. In this example, I’m saving it as currency.wsdl.

Your project structure should look something like this:-

myproject
|- src
|  |- main
|     |- java
|     |  |- myproject
|     |- resources
|        |- currency.wsdl
|- pom.xml

pom.xml

Add Spring Web Services dependency and configure JAXB-2 Maven plugin to generate the Java files based on the WSDL.

<project>
	...
	<dependencies>
	    <dependency>
	        <groupid>org.springframework.ws</groupid>
	        <artifactid>spring-ws-core</artifactid>
	        <version>2.1.2.RELEASE</version>
	    </dependency>
	</dependencies>

    <build>
        <plugins>
			...

            <plugin>
                <groupid>org.codehaus.mojo</groupid>
                <artifactid>jaxb2-maven-plugin</artifactid>
                <version>1.5</version>
                <executions>
                    <execution>
                        <id>xjc</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
					<!-- Package to store the generated file -->
                    <packagename>myproject.wsdl.currency</packagename>
					<!-- Treat the input as WSDL -->
                    <wsdl>true</wsdl>
                    <!-- Input is not XML schema -->
					<xmlschema>false</xmlschema>
                    <!-- The WSDL file that you saved earlier -->
                    <schemafiles>currency.wsdl</schemafiles>
                    <!-- The location of the WSDL file -->
					<schemadirectory>${project.basedir}/src/main/resources</schemadirectory>
                    <!-- The output directory to store the generated Java files -->
					<outputdirectory>${project.basedir}/src/main/java</outputdirectory>
                    <!-- Don't clear output directory on each run -->
                    <clearoutputdir>false</clearoutputdir>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Setting clearOutputDir to false is very important. If this is set to true and there’s a silly error in the JAXB-2 Maven plugin configuration, your output directory will be wiped clean. Since the output directory points to ${project.basedir}/src/main/java, we want to make sure we don’t lose all of our existing Java files.

Generating Java Files Based on WSDL

While you can run mvn clean jaxb2:xjc to generate the Java files, the easier way is to just run mvn clean compile. You should see a similar Maven output in your console:-

[INFO] ------------------------------------------------------------------------
[INFO] Building myproject 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- jaxb2-maven-plugin:1.5:xjc (xjc) @ myproject ---
[INFO] Generating source...
[INFO] parsing a schema...
[INFO] compiling a schema...
[INFO] myproject/wsdl/currency/ConversionRate.java
[INFO] myproject/wsdl/currency/ConversionRateResponse.java
[INFO] myproject/wsdl/currency/Currency.java
[INFO] myproject/wsdl/currency/ObjectFactory.java
[INFO] myproject/wsdl/currency/package-info.java
[INFO]

Your project structure should look something like this:-

myproject
|- src
|  |- main
|     |- java
|     |  |- myproject
|     |     |- wsdl
|     |        |- currency
|     |           |- ConversionRate.java
|     |           |- ConversionRateResponse.java
|     |           |- Currency.java
|     |           |- ObjectFactory.java
|     |           |- package-info.java
|     |- resources
|        |- currency.wsdl
|- pom.xml

applicationContext.xml ( src/main/resources )

Once we have the generated Java files, the next step is to configure Spring Web Services.

<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:oxm="http://www.springframework.org/schema/oxm" xmlns:util="http://www.springframework.org/schema/util" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <context:component-scan base-package="myproject">

	<!-- Define the SOAP version used by the WSDL -->
    <bean id="soapMessageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
        <property name="soapVersion">
            <util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_12">
        </util:constant></property>
    </bean>

	<!-- The location of the generated Java files -->
    <oxm:jaxb2-marshaller id="marshaller" contextpath="myproject.wsdl.currency">

	<!-- Configure Spring Web Services -->
    <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
        <constructor-arg ref="soapMessageFactory">
        <property name="marshaller" ref="marshaller">
        <property name="unmarshaller" ref="marshaller">
        <property name="defaultUri" value="http://www.webservicex.net/CurrencyConvertor.asmx?WSDL">
    </property></property></property></constructor-arg></bean>
</oxm:jaxb2-marshaller></context:component-scan></beans>

CurrentService.java ( src/main/java/myproject/service )

In the Service class, we will use Spring Web Services WebServiceTemplate to call the web service.

@Service
public class CurrencyService {
    @Autowired
    private WebServiceTemplate webServiceTemplate;

    public Double getConversionRate(Currency fromCurrency, Currency toCurrency) {
        ConversionRate conversionRate = new ObjectFactory().createConversionRate();
        conversionRate.setFromCurrency(fromCurrency);
        conversionRate.setToCurrency(toCurrency);

        ConversionRateResponse response = (ConversionRateResponse) webServiceTemplate.marshalSendAndReceive(
                conversionRate);

        return response.getConversionRateResult();
    }
}

Main.java ( src/main/java/myproject/main )

This is the main runner class.

public class Main {
    private static Logger log = Logger.getLogger(Main.class);

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        CurrencyService currencyService = context.getBean(CurrencyService.class);

        Currency fromCurrency = Currency.USD;
        Currency toCurrency = Currency.GBP;
        Double conversionRate = currencyService.getConversionRate(fromCurrency, toCurrency);

        log.info(String.format("The conversion rate from %s to %s is %s.", fromCurrency, toCurrency, conversionRate));
    }
}

Project Structure

Your project structure should look something like this:-

myproject
|- src
|  |- main
|     |- java
|     |  |- myproject
|     |     |- main
|     |        |- Main.java
|     |     |- service
|     |        |- CurrencyService.java
|     |     |- wsdl
|     |        |- currency
|     |           |- ConversionRate.java
|     |           |- ConversionRateResponse.java
|     |           |- Currency.java
|     |           |- ObjectFactory.java
|     |           |- package-info.java
|     |- resources
|        |- currency.wsdl
|- pom.xml

Result

When you run Main.java, you should see a result similar to this:-

The conversion rate from USD to GBP is 0.6178.

Comments

5 responses to “Using Spring Web Services and JAXB to Invoke Web Service Based on WSDL”

  1. my java learnings Avatar

    thank you, this is simple & clean example

  2. my java learnings Avatar

    thank you, i found it very useful 🙂

  3. Alok Avatar
    Alok

    Awesome

  4. Deepesh Avatar
    Deepesh

    Best tut so far on this topic.

  5. Dude Avatar
    Dude

    Nice.. Simple and understanding.. thanks a lot..

Leave a Reply