Tuesday, June 19, 2018

Making a contract first web service with Spring Boot

I have been told that Spring Boot is a great tool to learn. What do I think? In order to get my hand dirty on that, I've chosen to use it to develop a web service project. Well, I'd spend almost an hour plus to launch a web service, able to accept a request and provide a response. It was really damn amazing.

Unlike the tutorial I found on the Internet, my job scope doesn't work in that way. It is the WSDL file was created first, a.k.a. contract-first, but the tutorial I found on the Internet are contract-last. Wait, there are still hope, I found following sample that could help out.

Sample 1
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter
{
   @Bean(name = "services")
   public Wsdl11Definition defaultWsdl11Definition() {
      SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
      wsdl11Definition.setWsdl(new ClassPathResource("/schema/MyWsdl.wsdl")); //your wsdl location
      return wsdl11Definition;
   }
}
Sample 2
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter
{
   @Bean(name = "wsdlname")
   public DefaultWsdl11Definition defaultWsdl11Definition (XsdSchema cityRequestSchema) {
      DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
      wsdl11Definition.setRequestSuffix("ByCountry");
      wsdl11Definition.setResponseSuffix("City");
      wsdl11Definition.setPortTypeName("Hotelport");
      wsdl11Definition.setLocationUri("/ProjectName");
      wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-producing-web-service");
      wsdl11Definition.setSchema(cityRequestSchema);
      return wsdl11Definition;
   }

   @Bean
   public XsdSchema cityRequestSchema() {
      return new SimpleXsdSchema(new ClassPathResource("CityRequest.xsd"));
   }
}
Wait, I'm looking at the DefaultWsdl11Definition class, which I felt kind of weird, it doesn't seem sound right to me. Is it going to create the WSDL specification version 1.1, but my version is 1.2. I don't think this will work. Wait, the story has not ended, after a few days of searching, I manage to find a tutorial which has done a very good job on this matter. There are 2 ways to do this:

First solution
Do it in Spring configuration and load this configuration in the main class.
<beans xmlns="http://www.springframework.org/schema/beans" 
 xmlns:context="http://www.springframework.org/schema/context" 
 xmlns:jaxws="http://cxf.apache.org/jaxws" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                     http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
                     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   <context:component-scan base-package="org.huahsin68.core"/>

   <jaxws:endpoint 
      id="HelloService" 
      implementor="#helloResponseImpl"
      serviceName="s:HelloService"
      address="/hello"
      xmlns:s="http://huahsin68.org/helloService>
      <jaxws:features>
         < bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
      </jaxws:features>
   </jaxws:endpoint> 
</beans>
@SpringBootApplication
@ImportResource({"classpath:beans.xml"})
public class Application {
   ...
   ...
}
Second solution
Do it in Java. Create an Endpoint bean inside the configuration bean.
@Configuration
public class WebServiceConfig {

   ...
   ...

   @Bean
   public Endpoint endpoint() {
      HelloService h = new HelloService();
      EndpointImpl endpoint = new EndpointImpl(springBus(), new InfoServiceImpl());

      endpoint.getFeatures().add(new LoggingFeature());
      endpoint.setWsdlLocation("classpath:hello.wsdl");
      endpoint.setServiceName(h.getServiceName());
      endpoint.publish("/hello");

      return endpoint;
   }
}

Reference:
Building soap web service with Apache CXF and Spring Boot

No comments: