Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache CXF + Spring Java config (no XML)

Trying to deploy a JAX-WS endpoint using Tomcat 7 Maven plugin and CXF 2.7.8. As a matter of preference, I don't want to have any XML config for Spring or CXF. I see several blogs, articles, posts using cxf-servlet.xml and CXFServlet but none whatsoever completely using Java config. Looking into the CXFServlet source code, it looks for the cxf-servlet.xml or anything in the servlet context under the key 'config-location'. I tried programmatically registering the endpoint instead of in cxf-servlet.xml, but it doesn't work; I get a 404 when accessing the service. Any ideas?

@Configuration
@ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
public class CXFConfig {
    @Autowired
    Bus cxfBus;

    // More code

    @Bean
    public Endpoint calculator() {
        EndpointImpl endpoint = new EndpointImpl(cxfBus, new Calculator());
        endpoint.setAddress("/CalculatorService");
        return endpoint;
    }
}
like image 893
Abhijit Sarkar Avatar asked Jan 19 '14 22:01

Abhijit Sarkar


People also ask

Where do I put CXF xml?

For both web service clients and servers, the default location that CXF will look for a configuration for is "/cxf. xml" on the class path. For example, when running your application in a servlet container, this file is expected to be located in a /WEB-INF/classes folder of your web application.

How do I run Apache CXF?

You will have to make sure that you create an appropriate directory structure for your project and add the earlier shown hello. wsdl file to the specified folder. The wsdl2java plugin will compile this wsdl and create Apache CXF classes in a pre-defined folder.

What is spring CXF?

The application context loads Spring elements defined in a configuration file. In this case, the name of the servlet is cxf, therefore the context looks for those elements in a file named cxf-servlet. xml by default. Lastly, the CXF servlet is mapped to a relative URL: dispatcher.addMapping("/services");

What is CXF servlet?

Fuse Services Framework provides a standard servlet, the CXF servlet, which acts as an adapter for the Web service endpoints. The CXF servlet is the easiest method for deploying Web services into a servlet container.


4 Answers

Everything posted here is not 100% XML configuration free - all posts are using the classpath:META-INF/cxf/cxf.xml, which is also used in most tutorials on the web. But there´s a solution for that: Define a org.apache.cxf.bus.spring.SpringBus as @Bean and configure name = Bus.DEFAULT_BUS_ID, comming from org.apache.cxf.Bus.

As described in the other answers, the org.apache.cxf.jaxws.EndpointImpl has to be instantiated - including forwarding of the Beans SpringBus and the SEI-implementing Class. Also, the publish()-Method of EndpointImpl has to becalled, including a String containing an URL ending:

package de.jonashackt.tutorial.configuration;

import javax.xml.ws.Endpoint;

import org.apache.cxf.Bus;
import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import de.codecentric.namespace.weatherservice.WeatherService;
import de.jonashackt.tutorial.endpoint.WeatherServiceEndpoint;

@Configuration
public class WebServiceConfiguration {

    @Bean
    public ServletRegistrationBean dispatcherServlet() {
        return new ServletRegistrationBean(new CXFServlet(), "/soap-api/*");
    }

    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus() {
        return new SpringBus();
    }    

    @Bean
    public WeatherService weatherService() {
        return new WeatherServiceEndpoint();
    }

    @Bean
    public Endpoint endpoint() {
        EndpointImpl endpoint = new EndpointImpl(springBus(), weatherService());
        endpoint.publish("/WeatherSoapService");
        return endpoint;
    }
}

If you want to learn more about Apache CXF together with SpringBoot, I recommend a look on this github project.

like image 56
jonashackt Avatar answered Oct 18 '22 01:10

jonashackt


All that's needed is a endpoint.publish() call above.

like image 38
Abhijit Sarkar Avatar answered Oct 18 '22 01:10

Abhijit Sarkar


This thread definitely put me on the right track to getting CXF to run in pure Spring Java configuration, but it didn't provide everything that is required.

For my self, pure Java configuration means without a web.xml file, which I think this answer assumes is present. Spring Boot for example doesn't use a web.xml file.

So to register a CXF endpoint without the use of any XML files at all you will need a configuration file that also loads the CXFServlet.

import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

import javax.xml.ws.Endpoint;

@Configuration
@ImportResource({"classpath:META-INF/cxf/cxf.xml"})
public class JavaConfiguration {

    @Autowired
    private Bus bus;

    @Bean
    public Endpoint myServiceEndpoint() {
        EndpointImpl endpoint = new EndpointImpl(bus, new MyService());
        endpoint.publish("/myservice");
        return endpoint;
    }

    @Bean
    public ServletRegistrationBean cxfServlet() {
        ServletRegistrationBean servlet = new ServletRegistrationBean(new CXFServlet(), "/services/*");
        servlet.setLoadOnStartup(1);
        return servlet;
    }
}

The above is all the configuration required to successfully load a CXF endpoint within Spring.

I have also created a small project that demonstrates this.

like image 31
Karl Bennett Avatar answered Oct 18 '22 01:10

Karl Bennett


I belive that if you pass your beans inside factory.setServiceBeans it will work

package br.com.app.spring;

import java.util.Arrays;

import javax.ws.rs.ext.RuntimeDelegate;

import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

import br.com.app.JaxRsApiApplication;
import br.com.app.services.EditionRest;
import br.com.app.services.EditionService;

@Configuration
@ImportResource(
    { 
        "classpath:META-INF/cxf/cxf.xml", 
        "classpath:META-INF/cxf/cxf-extension-xml.xml",
        "classpath:META-INF/cxf/cxf-servlet.xml" 
    })
public class CXFConfig {

@Bean(destroyMethod = "shutdown")
public SpringBus cxf() {
    return new SpringBus();
}

@Bean
public EditionService editionRest() {
    return new EditionRest();
}

@Bean
public JaxRsApiApplication jaxRsApiApplication() {
    return new JaxRsApiApplication();
}

@Autowired
@Bean
public Server jaxRsServer(JacksonJsonProvider provider) {

    JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint(jaxRsApiApplication(), JAXRSServerFactoryBean.class);
    factory.setServiceBeans(Arrays.<Object> asList(editionRest()));
    factory.setProviders(Arrays.<Object> asList(provider));

    return factory.create();
}

@Bean
public JacksonJsonProvider jsonProvider() {
    return new JacksonJsonProvider();
}
}
like image 23
arthurfnsc Avatar answered Oct 18 '22 01:10

arthurfnsc