Skip to content

Spring Boot With Apache CXF#

Introduction#

What Is The Apache CXF?#

  • Apache CXF is an open source services framework. CXF helps us to build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.
  • Some of the key features of CXF include support for the latest web service standards, data transformation, interceptors, security, and RESTful services. CXF also integrates well with other popular Java technologies like Spring and Camel.
  • You can view more here

Why Apache CXF?#

  • CXF implements the JAX-WS APIs which make building web services easy. JAX-WS encompasses many different areas:
    • Generating WSDL from Java classes and generating Java classes from WSDL
    • Provider API which allows you to create simple messaging receiving server endpoints
    • Dispatch API which allows you to send raw XML messages to server endpoints
    • Much more...
  • Spring is a first class citizen with Apache CXF. CXF supports the Spring 2.0 XML syntax, making it trivial to declare endpoints which are backed by Spring and inject clients into your application.
  • View more here

Integrating Spring Boot And Apache CXF#

Prepare The Environment#

  • To make an example we need an online Web Service, so we can go to free SOAP service urls and choose one to make an example.
  • In this example I will choose country list SOAP service because it is the one that is working well.
  • So you need go to country list SOAP service by your browser. Then Right Click and choose Save As. After that you save the file with type .wsdl into any package in src/main/resources of your spring boot project as the images below:

 #zoom

 #zoom

Dependencies#

  • We need to add some dependencies for using apache cxf in our Spring Boot project as below.
pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<dependency>  
    <groupId>org.apache.cxf</groupId>  
    <artifactId>cxf-rt-transports-http</artifactId>  
    <version>3.5.5</version>  
</dependency>  

<dependency>  
    <groupId>org.apache.cxf</groupId>  
    <artifactId>cxf-rt-wsdl</artifactId>  
    <version>3.5.5</version>  
</dependency>
  • We also need to add the plugin for generate Java Classes from the WSDL file as below.
pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<build>
        <plugins>
                <plugin>
                        <groupId>org.apache.cxf</groupId>
                        <artifactId>cxf-codegen-plugin</artifactId>
                        <version>${cxf.version}</version>
                        <executions>
                                <execution>
                                        <id>generate-sources</id>
                                        <phase>generate-sources</phase>
                                        <configuration>
                                                <!-- the source root that will contain our generated java classes -->
                                                <sourceRoot>${project.build.directory}/generated-sources/java</sourceRoot>
                                                <wsdlOptions>
                                                        <wsdlOption>
                                                                <!-- the path where we put the wsdl file -->
                                                                <wsdl>${basedir}/src/main/resources/countries.wsdl</wsdl>
                                                                <!-- the package that contains our generated java classes -->
                                                                <packagenames>com.springboot.apache.cxf.generated</packagenames>
                                                        </wsdlOption>
                                                </wsdlOptions>
                                        </configuration>
                                        <goals>
                                                <!-- convert wsdl file to java classes -->
                                                <goal>wsdl2java</goal>
                                        </goals>
                                </execution>
                        </executions>
                </plugin>
        </plugins>
</build>

Generate Java Classes From WSDL File#

  • So let's open the terminal/command line then run mvn compile, then Maven will read the file countries.wsdl to generate java classes and put them into the package that we have already defined in the pom.xml.
  • If you note that, java classes have been configured with many annotation of XML, So these class will be formatted as xml type when we transfer them to SOAP service.

 #zoom

Configuration Properties#

  • Firstly, we will need to create a configuration properties class to load some needed properties that we will configure in the application.yml file by using @ConfigurationProperties, if you have not used it before then you can view Spring Boot With @ConfigurationProperties.
  • So let's create CountryInfoProperties.java which will load some properties: hostname, protocol, port and api as below.
CountryInfoProperties.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package com.springboot.apache.cxf.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "country.client.soap")
public class CountryInfoProperties {

    private String hostname;
    private String protocol;
    private String port;
    private String api;

}
  • In the application.yml, we will put some configuration properties like below.
application.yml
1
2
3
4
5
6
7
country:
  client:
    soap:
      hostname: webservices.oorsprong.org
      protocol: http
      port: 80
      api: websamples.countryinfo/CountryInfoService.wso

 #zoom

  • So if you look into the URL that we used to download the wsdl file we can know the protocol (No SSL so http), host , port (No SSL so the port is 80) and the api and we will put them into the configuration above.

URL Factory#

  • Next, with the CountryInfoProperties above we will use it in the UrlFactory to build the URI for calling WebServices as below.
UrlFactory.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.springboot.apache.cxf.factory;

import com.springboot.apache.cxf.config.CountryInfoProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class UrlFactory {

    private final CountryInfoProperties countryInfoProperties;

    public String buildWebServiceUrl() {
        UriComponents uriComponents = UriComponentsBuilder
                .newInstance()
                .scheme(this.countryInfoProperties.getProtocol())
                .host(this.countryInfoProperties.getHostname())
                .port(this.countryInfoProperties.getPort())
                .path(this.countryInfoProperties.getApi())
                .build();
        return uriComponents.toString();
    }

}
  • As you can see, we will all configuration properties that we put in the application.yml to build the URI.

Client Configuration#

  • Next, we will configure the client for calling Soap WebServices. If you look into the generated code by Apache CXF you can see there is an interface like this.

 #zoom

  • So this interface represents a SOAP WebService client that communicates with a WebService provider. If you look into every method you can see each method has annotations such as @WebMethod, @WebParam, @WebResult, @RequestWrapper, and @ResponseWrapper. These annotations are used to specify the SOAP message format and details.

  • Then we also see there is a generated java class that is annotation with annotation @WebServiceClient as below.

 #zoom

  • So this class CountryInfoService is a generated WebService client that allows Java applications to interact with a SOAP-based WebService. The purpose of this class is to provide a Java interface for a client to access the web service's functions to retrieve information. If you look into this class, you can see the method getPort will return the SOAP WebService client interface above.

  • Now, We will configure it for calling SOAP WebService. Let's create a configuration class for SOAP WebService client as below.

package com.springboot.apache.cxf.config;

import com.springboot.apache.cxf.factory.UrlFactory;
import com.springboot.apache.cxf.generated.CountryInfoService;
import com.springboot.apache.cxf.generated.CountryInfoServiceSoapType;
import com.springboot.apache.cxf.generated.ObjectFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.xml.ws.BindingProvider;
import java.util.Map;

@Configuration
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CountryInfoClientConfig {

    private final UrlFactory urlFactory;

    @Bean
    public CountryInfoServiceSoapType countryInfoServiceSoapType() {
        CountryInfoService countryInfoService = new CountryInfoService();
        CountryInfoServiceSoapType countryInfoServiceSoapType =  countryInfoService.getCountryInfoServiceSoap();
        Map<String, Object> requestContext = ((BindingProvider) countryInfoServiceSoapType).getRequestContext();
        requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, this.urlFactory.buildCountryInfoWebServiceUrl());
        return countryInfoServiceSoapType;
    }

    @Bean
    public ObjectFactory countryInfoServiceSoapTypeFactory() {
        return new ObjectFactory();
    }

}
  • Firstly, we will create an instance of CountryInfoService. Then from this instance we will get the instance CountryInfoServiceSoapType. Then we will set the request URL for it by using the UrlFactory that we created in the step above and return it as a bean countryInfoServiceSoapType.
  • Secondly, we will create a bean countryInfoServiceSoapTypeFactory with new instance ObjectFactory. In Apache CXF, the ObjectFactory is a class that is generated from the XML schema file and is used to create instances of the JAXB-generated classes that represent the schema elements.
    • In other words, the ObjectFactory is responsible for creating instances of the classes that correspond to the XML elements defined in the schema. This is necessary because JAXB classes are typically generated as plain Java classes without any constructors. Instead, JAXB provides the ObjectFactory class to create instances of these classes.
    • By creating a bean for the ObjectFactory, we can inject it into other beans or components that require it to create instances of the JAXB-generated classes. This can be useful when working with SOAP web services or other XML-based technologies that rely on JAXB to serialize and deserialize XML data.

Utility Class#

  • An utility class is helpful for us to use for mapping request objects for calling Soap WebService or response objects from Soap WebService. So let's create the Utility java class as below.
CountryInfoFactory.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.springboot.apache.cxf.factory;

import com.springboot.apache.cxf.generated.ArrayOftCountryCodeAndNameGroupedByContinent;
import com.springboot.apache.cxf.generated.CountryNameResponse;
import com.springboot.apache.cxf.generated.ListOfCountryNamesGroupedByContinentResponse;
import lombok.experimental.UtilityClass;

@UtilityClass
public class CountryInfoFactory {

    public CountryNameResponse mapCountryNameResponse(String countryName) {
        CountryNameResponse countryNameResponse = new CountryNameResponse();
        countryNameResponse.setCountryNameResult(countryName);
        return countryNameResponse;
    }

    public ListOfCountryNamesGroupedByContinentResponse mapListOfCountryNamesGroupedByContinentResponse(ArrayOftCountryCodeAndNameGroupedByContinent response) {
        ListOfCountryNamesGroupedByContinentResponse listOfCountryNamesGroupedByContinentResponse = new ListOfCountryNamesGroupedByContinentResponse();
        listOfCountryNamesGroupedByContinentResponse.setListOfCountryNamesGroupedByContinentResult(response);
        return listOfCountryNamesGroupedByContinentResponse;
    }

}
  • In this CountryInfoFactory utility class we will have two methods which are used for mapping result objects from Soap WebService to our response DTO classes.

Service#

  • Now, let's create a service class for calling Soap WebService by using the configured Soap WebService client that we configured before. Now, we will inject the CountryInfoServiceSoapType client into our service and use it as below.
CountryCodeHandler.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.springboot.apache.cxf.service;

import com.springboot.apache.cxf.factory.CountryInfoFactory;
import com.springboot.apache.cxf.generated.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.MessageContext;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CountryCodeHandler {

    private final CountryInfoServiceSoapType countryClient;

    public CountryNameResponse getCountryName(String countryISO) {
        try {
            String countryName = this.countryClient.countryName(countryISO);
            return CountryInfoFactory.mapCountryNameResponse(countryName);
        } catch (Exception e) {
            BindingProvider bindingProvider = (BindingProvider) this.countryClient;
            log.info("Error Code: {}", bindingProvider.getResponseContext().get(MessageContext.HTTP_RESPONSE_CODE));
            throw new RuntimeException(e);
        }
    }

    public ListOfCountryNamesGroupedByContinentResponse getListOfCountryNamesGroupedByContinent() {
        try {
            ArrayOftCountryCodeAndNameGroupedByContinent response = this.countryClient.listOfCountryNamesGroupedByContinent();
            return CountryInfoFactory.mapListOfCountryNamesGroupedByContinentResponse(response);
        } catch (Exception e) {
            BindingProvider bindingProvider = (BindingProvider) this.countryClient;
            log.info("Error Code: {}", bindingProvider.getResponseContext().get(MessageContext.HTTP_RESPONSE_CODE));
            throw new RuntimeException(e);
        }
    }

}
  • There are many api that we can use in CountryInfoServiceSoapType but in this example we just use 2 of them, they are countryName and listOfCountryNamesGroupedByContinent.

Controller#

  • Finally, we just need to create a controller class and inject the CountryCodeHandler service that we created in the step above for using.
WebServicesController.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.springboot.apache.cxf.controller;

import com.springboot.apache.cxf.generated.CountryNameResponse;
import com.springboot.apache.cxf.generated.ListOfCountryNamesGroupedByContinentResponse;
import com.springboot.apache.cxf.service.CountryCodeHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class WebServicesController {

    private final CountryCodeHandler countryCodeHandler;

    @GetMapping(path = "/v1/soap/country/{countryISO}", produces = MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<CountryNameResponse> getCountryNameByISO(@PathVariable("countryISO") String countryISO) {
        return ResponseEntity.ok(this.countryCodeHandler.getCountryName(countryISO));
    }

    @GetMapping(path = "/v1/soap/country/listOfCountryNamesGroupedByContinent", produces = MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<ListOfCountryNamesGroupedByContinentResponse> getCountryNameByISO() {
        return ResponseEntity.ok(this.countryCodeHandler.getListOfCountryNamesGroupedByContinent());
    }

}

Testing#

  • Now, let's start our Spring Boot application and call two apis for testing. You should see the successful results as below.

 #zoom

 #zoom

Handle Exception With Apache CXF#

  • Okay, we have finished implementing the happy case, but for the case that we getting errors from the Soap WebService like Service is unavailable or not found, how we can handle it?
  • Let's take an example, if we change api or the hostname in the application.yml and call the Soap WebService again, you will always receive the 500 error as below.

 #zoom

 #zoom

  • So, this is not true and it is hard for developers to detect the issues when working with Soap WebService. Then handling the exception with Apache CXF is important and we should practice with it.

Add Custom Exception#

  • Firstly, let's create a custom exception which contains some information about the error as below.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.springboot.apache.cxf.exception;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class TechnicalException extends RuntimeException {

    private final Integer responseCode;
    private final String url;
    private final String responseHeaders;
    private final String rootCause;

    public TechnicalException(String message, Integer responseCode, String url, String responseHeaders, String rootCause) {
        super(message);
        this.responseCode = responseCode;
        this.url = url;
        this.responseHeaders = responseHeaders;
        this.rootCause = rootCause;
    }
}
  • With this custom exception we can use it to store information that we want to extract when got issues with calling SOAP WebService.

Error Response Body#

  • Next, we will create an simple error DTO which will be the error response body for clients who is using apis from our Spring Boot application.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package com.springboot.apache.cxf.model;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class ErrorDetail {

    private Integer status;
    private String calledUrl;
    private String responseHeaders;
    private String rootCause;
    private String errorMessage;
    private String timestamp;
    private String api;

}

Exception Handler#

  • Now, We will create an exception handler class named GlobalExceptionHandler which will extends from ResponseEntityExceptionHandler class, by default the ResponseEntityExceptionHandler will provide an @ExceptionHandler method for handling internal Spring MVC exceptions.
GlobalExceptionHandler.class
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.springboot.apache.cxf.handler;

import com.springboot.apache.cxf.exception.TechnicalException;
import com.springboot.apache.cxf.model.ErrorDetail;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import java.time.OffsetDateTime;

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value = {TechnicalException.class})
    public ResponseEntity<ErrorDetail> technicalExceptionHandler(TechnicalException ex, WebRequest request) {
        ErrorDetail errorDetail = new ErrorDetail();
        errorDetail.setTimestamp(OffsetDateTime.now().toString());
        errorDetail.setErrorMessage(ex.getMessage());
        errorDetail.setStatus(ex.getResponseCode());
        errorDetail.setRootCause(ex.getRootCause());
        errorDetail.setResponseHeaders(ex.getResponseHeaders());
        errorDetail.setCalledUrl(ex.getUrl());
        errorDetail.setApi(request.getDescription(false));
        if (errorDetail.getStatus() >= 400) {
            return new ResponseEntity<>(errorDetail, HttpStatus.valueOf(ex.getResponseCode()));
        }
        errorDetail.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        return new ResponseEntity<>(errorDetail, HttpStatus.SERVICE_UNAVAILABLE);
    }

    @ExceptionHandler(value = {Exception.class})
    public ResponseEntity<ErrorDetail> exceptionHandler(Exception ex, WebRequest request) {
        ErrorDetail errorDetail = new ErrorDetail();
        errorDetail.setTimestamp(OffsetDateTime.now().toString());
        errorDetail.setErrorMessage(ex.getMessage());
        errorDetail.setApi(request.getDescription(false));
        return new ResponseEntity<>(errorDetail, HttpStatus.INTERNAL_SERVER_ERROR);
    }

}
  • As you can see, we will create 2 methods. The first method technicalExceptionHandler is used for catching all exceptions with type TechnicalException and then we will extracted information from it for building response body which is the ErrorDetail DTO class. Like wise, the second method exceptionHandler is used for catching all other exception types which are not TechnicalException.

  • If you have not know about how to handle exceptions in Spring Boot application. You can view this Spring Boot With Exception Handler And Message Source.

Utility Class#

  • Next, we will need to update the utility class for extracting information and building the TechnicalException. So let's add some more methods buildTechnicalException, getResponseCode, getEndpoint and getResponseHeaders as below.
package com.springboot.apache.cxf.factory;

import com.springboot.apache.cxf.exception.TechnicalException;
import com.springboot.apache.cxf.generated.ArrayOftCountryCodeAndNameGroupedByContinent;
import com.springboot.apache.cxf.generated.CountryInfoServiceSoapType;
import com.springboot.apache.cxf.generated.CountryNameResponse;
import com.springboot.apache.cxf.generated.ListOfCountryNamesGroupedByContinentResponse;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;

import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.MessageContext;

@Slf4j
@UtilityClass
public class CountryInfoFactory {

    public CountryNameResponse mapCountryNameResponse(String countryName) {
        CountryNameResponse countryNameResponse = new CountryNameResponse();
        countryNameResponse.setCountryNameResult(countryName);
        return countryNameResponse;
    }

    public ListOfCountryNamesGroupedByContinentResponse mapListOfCountryNamesGroupedByContinentResponse(ArrayOftCountryCodeAndNameGroupedByContinent response) {
        ListOfCountryNamesGroupedByContinentResponse listOfCountryNamesGroupedByContinentResponse = new ListOfCountryNamesGroupedByContinentResponse();
        listOfCountryNamesGroupedByContinentResponse.setListOfCountryNamesGroupedByContinentResult(response);
        return listOfCountryNamesGroupedByContinentResponse;
    }


    public TechnicalException buildTechnicalException(CountryInfoServiceSoapType client, Exception ex) {
        return new TechnicalException(
                ex.getMessage(),
                getResponseCode(client),
                getEndpoint(client),
                getResponseHeaders(client),
                ExceptionUtils.getRootCauseMessage(ex));
    }


    private Integer getResponseCode(CountryInfoServiceSoapType countryClient) {
        BindingProvider bindingProvider = (BindingProvider) countryClient;
        Integer responseCode = (Integer) bindingProvider.getResponseContext().get(MessageContext.HTTP_RESPONSE_CODE);
        log.info("Error Code: {}", responseCode);
        return responseCode;
    }


    private String getEndpoint(CountryInfoServiceSoapType countryClient) {
        BindingProvider bindingProvider = (BindingProvider) countryClient;
        String endpoint = (String) bindingProvider.getRequestContext().get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);;
        log.info("Error Endpoint: {}", endpoint);
        return endpoint;
    }

    private String getResponseHeaders(CountryInfoServiceSoapType countryClient) {
        BindingProvider bindingProvider = (BindingProvider) countryClient;
        Object objectHeaders = bindingProvider.getResponseContext().get(MessageContext.HTTP_RESPONSE_HEADERS);
        return String.valueOf(objectHeaders);
    }


}
  • So, to build the TechnicalException, we will need to extract some information from failed response when we call to the SOAP WebService. To to that we can cast the CountryInfoServiceSoapType SOAP WebService client interface from the input param to the BindingProvider. Then from the BindingProvider we can easily use getRequestContext or getResponseContext for extracting information from the request or response of the SOAP WebService call respectively.
  • We also need the Exception as an input param to extract the error message and rootCause.

Throwing Custom Exception#

  • Now, Let's update throwing exception in the Service class as below.
package com.springboot.apache.cxf.service;  

import com.springboot.apache.cxf.factory.CountryInfoFactory;  
import com.springboot.apache.cxf.generated.*;  
import lombok.RequiredArgsConstructor;  
import lombok.extern.slf4j.Slf4j;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  

@Slf4j  
@Service  
@RequiredArgsConstructor(onConstructor = @__(@Autowired))  
public class CountryCodeHandler {  

    private final CountryInfoServiceSoapType countryClient;  

    public CountryNameResponse getCountryName(String countryISO) {  
        try {  
            String countryName = this.countryClient.countryName(countryISO);  
            return CountryInfoFactory.mapCountryNameResponse(countryName);  
        } catch (Exception e) {  
            throw CountryInfoFactory.buildTechnicalException(countryClient, e);  
        }  
    }  

    public ListOfCountryNamesGroupedByContinentResponse getListOfCountryNamesGroupedByContinent() {  
        try {  
            ArrayOftCountryCodeAndNameGroupedByContinent response = this.countryClient.listOfCountryNamesGroupedByContinent();  
            return CountryInfoFactory.mapListOfCountryNamesGroupedByContinentResponse(response);  
        } catch (Exception e) {  
            throw CountryInfoFactory.buildTechnicalException(countryClient, e);  
        }  
    }  

}

Testing#

  • Finally, Let's change api or the hostname in the application.yml and call the Soap WebService again, you will always receive the 500 error as below.

 #zoom

 #zoom

See Also#

References#