Skip to content
Advertisement

Vaadin with Apache CXF SOAP service

I am new to Vaadin, just generated the application in Vaadin web site and built it locally. Then I added Apache CXF SOAP service to it, but I am unable to use the Tomcat that Vaadin is using, but instead I load SOAP in Jetty using:

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-transports-http-jetty</artifactId>
    <version>${cxf.version}</version>
    <scope>compile</scope>
</dependency>

My Vaadin application is:

@SpringBootApplication
@Theme(value = "iciclient", variant = Lumo.DARK)
@PWA(name = "ICI Client", shortName = "ICI Client", offlineResources = {"images/logo.png"})
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {

    public static void main(String[] args) {
        LaunchUtil.launchBrowserInDevelopmentMode(SpringApplication.run(Application.class, args));
        try {
            System.out.println("Starting IciEventClient");
            Object implementor = new IciEventServiceSoap12Impl();
            String address = "http://localhost:8081/ici/IciEventService";
            Endpoint.publish(address, implementor);
            // http://localhost:8081/ici/IciEventService?WSDL
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

While this works, I would like to get rid of separate Jetty dependency and run the SOAP service in Vaadin Tomcat (localhost:8080). Should be simple but I can’t figure out how to do it. I think that it needs a separate servlet and route, but I don’t know how to add them. There is no web.xml in the Vaadin application, for example.

Advertisement

Answer

I am not familiar with Apache CXF, but based on CXF docs and the sample project I think I got it to work.

I downloaded a new Vaadin 14/Java 8 project from start.vaadin.com, and did the following:

  1. Added the dependency

    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
        <version>3.4.3</version>
    </dependency>
    
  2. Created a web service

    import javax.jws.WebMethod;
    import javax.jws.WebService;
    
    @WebService
    public class Test {
    
        @WebMethod
        public String test() {
            return "This works";
        }
    }
    
  3. Exposed it as a bean in my Application class

    import javax.xml.ws.Endpoint;
    
    import org.apache.cxf.Bus;
    import org.apache.cxf.jaxws.EndpointImpl;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
    import org.springframework.context.annotation.Bean;
    import org.vaadin.artur.helpers.LaunchUtil;
    import org.vaadin.erik.endpoint.Test;
    
    @SpringBootApplication
    public class Application extends SpringBootServletInitializer {
    
        public static void main(String[] args) {
            LaunchUtil.launchBrowserInDevelopmentMode(SpringApplication.run(Application.class, args));
        }
    
        @Bean
        public Endpoint test(Bus bus) {
            EndpointImpl endpoint = new EndpointImpl(bus, new Test());
            endpoint.publish("/Test");
            return endpoint;
        }
    }
    

That was it! At least I can now list the service definition at http://localhost:8080/services/Test?wsdl

The first documentation link lists some configurations you can do, for example to change the /services path. The example project shows how to configure Spring actuator metrics if that is something you need.

You might want to create a separate @Configuration-annotated class for all your service @Bean definitions.

If you don’t want to use the starter dependency, this Baeldung article looks promising.

Advertisement