You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cxf.apache.org by "Przemyslaw Bielicki (JIRA)" <ji...@apache.org> on 2013/12/09 16:58:07 UTC

[jira] [Updated] (CXF-5448) Spring integration via @Configuration & @ComponentScan annotations

     [ https://issues.apache.org/jira/browse/CXF-5448?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Przemyslaw Bielicki updated CXF-5448:
-------------------------------------

    Description: 
Hi,

as per dev mailing list thread started by me http://mail-archives.apache.org/mod_mbox/cxf-dev/201312.mbox/%3c1386597934463-5737561.post@n5.nabble.com%3e I would like to share my solution to get rid of XML file with CXF services definition.

My case is rather simple (read: uncomplete) as I just want to automatically register in CXF @WebService and @WebServiceProvider annotated classes, so that they are exposed via CXFServlet.

The end developer just needs to annotate her services with e.g. @WebService annotation and also needs to add a following Spring configuration (application code):
{code:title=SampleAppConfig.java|borderStyle=solid}
import javax.jws.WebService;
import javax.xml.ws.WebServiceProvider;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(JaxWsConfig.class)
@ComponentScan(value = { "package filters" },
    includeFilters = { 
      @Filter(WebService.class), 
      @Filter(WebServiceProvider.class) 
    })
public class SampleAppConfig {
}
{code}
where JaxWsConfig is a reference to CXF Spring configuration (it should be a part of CXF):
{code:title=JaxWsConfig.java|borderStyle=solid}
@Configuration
@ImportResource({ 
  "classpath:META-INF/cxf/cxf.xml", 
  "classpath:META-INF/cxf/cxf-servlet.xml" 
  })
public class JaxWsConfig {
}
{code}

The crucial part is Spring bean post processor (that should be also a part of CXF distribution):
{code:title=JaxWsBeanPostProcessor.java|borderStyle=solid}
@Named
public class JaxWsBeanPostProcessor implements BeanPostProcessor {

  @Inject
  ListableBeanFactory beanFactory;
  
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      if (isWebService(bean)) {
        Bus bus = beanFactory.getBean(Bus.DEFAULT_BUS_ID, Bus.class);
        SpringEndpointImpl endpoint = new SpringEndpointImpl(bus, bean);
        // capitalization is just a nice feature - totally optional
        endpoint.setAddress("/" + StringUtils.capitalize(beanName));
        // adds ALL features registered / discovered by Spring
        Map<String, AbstractFeature> featureMap = beanFactory.getBeansOfType(AbstractFeature.class);
        endpoint.getFeatures().addAll(featureMap.values());
        endpoint.publish();
      }
      
      return bean;
  }

  boolean isWebService(Object bean) {
    Class<?> beanClass = bean.getClass();
    return beanClass.getAnnotation(WebService.class) != null
        || beanClass.getAnnotation(WebServiceProvider.class) != null;
  }
}
{code}

And then if you also want to configure / inject your features using CDI (Spring) you do stuff like this (application code):
{code:title=MyFeature.java|borderStyle=solid}
@Named
public class MyFeature extends AbstractFeature {
  
  @Inject
  MyInInterceptor inInterceptor;

  @Inject
  MyOutInterceptor outInterceptor;

  @Override
  protected void initializeProvider(InterceptorProvider provider, Bus bus) {
    processedBus.put(bus, Boolean.TRUE);
    bus.getInInterceptors().add(inInterceptor);
    bus.getOutInterceptors().add(outInterceptor);
  }
{code}

Does that make sense?

Please note that my implementation is simplified but works for me. You should probably add all other possible customizations in JaxWsBeanPostProcessor class.

  was:
Hi,

as per dev mailing list thread started by me http://mail-archives.apache.org/mod_mbox/cxf-dev/201312.mbox/browser I would like to share my solution to get rid of XML file with CXF services definition.

My case is rather simple (read: uncomplete) as I just want to automatically register in CXF @WebService and @WebServiceProvider annotated classes, so that they are exposed via CXFServlet.

The end developer just needs to annotate her services with e.g. @WebService annotation and also needs to add a following Spring configuration (application code):
{code:title=SampleAppConfig.java|borderStyle=solid}
import javax.jws.WebService;
import javax.xml.ws.WebServiceProvider;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(JaxWsConfig.class)
@ComponentScan(value = { "package filters" },
    includeFilters = { 
      @Filter(WebService.class), 
      @Filter(WebServiceProvider.class) 
    })
public class SampleAppConfig {
}
{code}
where JaxWsConfig is a reference to CXF Spring configuration (it should be a part of CXF):
{code:title=JaxWsConfig.java|borderStyle=solid}
@Configuration
@ImportResource({ 
  "classpath:META-INF/cxf/cxf.xml", 
  "classpath:META-INF/cxf/cxf-servlet.xml" 
  })
public class JaxWsConfig {
}
{code}

The crucial part is Spring bean post processor (that should be also a part of CXF distribution):
{code:title=JaxWsBeanPostProcessor.java|borderStyle=solid}
@Named
public class JaxWsBeanPostProcessor implements BeanPostProcessor {

  @Inject
  ListableBeanFactory beanFactory;
  
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      if (isWebService(bean)) {
        Bus bus = beanFactory.getBean(Bus.DEFAULT_BUS_ID, Bus.class);
        SpringEndpointImpl endpoint = new SpringEndpointImpl(bus, bean);
        // capitalization is just a nice feature - totally optional
        endpoint.setAddress("/" + StringUtils.capitalize(beanName));
        // adds ALL features registered / discovered by Spring
        Map<String, AbstractFeature> featureMap = beanFactory.getBeansOfType(AbstractFeature.class);
        endpoint.getFeatures().addAll(featureMap.values());
        endpoint.publish();
      }
      
      return bean;
  }

  boolean isWebService(Object bean) {
    Class<?> beanClass = bean.getClass();
    return beanClass.getAnnotation(WebService.class) != null
        || beanClass.getAnnotation(WebServiceProvider.class) != null;
  }
}
{code}

And then if you also want to configure / inject your features using CDI (Spring) you do stuff like this (application code):
{code:title=MyFeature.java|borderStyle=solid}
@Named
public class MyFeature extends AbstractFeature {
  
  @Inject
  MyInInterceptor inInterceptor;

  @Inject
  MyOutInterceptor outInterceptor;

  @Override
  protected void initializeProvider(InterceptorProvider provider, Bus bus) {
    processedBus.put(bus, Boolean.TRUE);
    bus.getInInterceptors().add(inInterceptor);
    bus.getOutInterceptors().add(outInterceptor);
  }
{code}

Does that make sense?

Please note that my implementation is simplified but works for me. You should probably add all other possible customizations in JaxWsBeanPostProcessor class.


> Spring integration via @Configuration & @ComponentScan annotations
> ------------------------------------------------------------------
>
>                 Key: CXF-5448
>                 URL: https://issues.apache.org/jira/browse/CXF-5448
>             Project: CXF
>          Issue Type: Improvement
>          Components: Integration
>    Affects Versions: 2.6.11
>            Reporter: Przemyslaw Bielicki
>            Priority: Minor
>
> Hi,
> as per dev mailing list thread started by me http://mail-archives.apache.org/mod_mbox/cxf-dev/201312.mbox/%3c1386597934463-5737561.post@n5.nabble.com%3e I would like to share my solution to get rid of XML file with CXF services definition.
> My case is rather simple (read: uncomplete) as I just want to automatically register in CXF @WebService and @WebServiceProvider annotated classes, so that they are exposed via CXFServlet.
> The end developer just needs to annotate her services with e.g. @WebService annotation and also needs to add a following Spring configuration (application code):
> {code:title=SampleAppConfig.java|borderStyle=solid}
> import javax.jws.WebService;
> import javax.xml.ws.WebServiceProvider;
> import org.springframework.context.annotation.ComponentScan;
> import org.springframework.context.annotation.ComponentScan.Filter;
> import org.springframework.context.annotation.Configuration;
> import org.springframework.context.annotation.Import;
> @Configuration
> @Import(JaxWsConfig.class)
> @ComponentScan(value = { "package filters" },
>     includeFilters = { 
>       @Filter(WebService.class), 
>       @Filter(WebServiceProvider.class) 
>     })
> public class SampleAppConfig {
> }
> {code}
> where JaxWsConfig is a reference to CXF Spring configuration (it should be a part of CXF):
> {code:title=JaxWsConfig.java|borderStyle=solid}
> @Configuration
> @ImportResource({ 
>   "classpath:META-INF/cxf/cxf.xml", 
>   "classpath:META-INF/cxf/cxf-servlet.xml" 
>   })
> public class JaxWsConfig {
> }
> {code}
> The crucial part is Spring bean post processor (that should be also a part of CXF distribution):
> {code:title=JaxWsBeanPostProcessor.java|borderStyle=solid}
> @Named
> public class JaxWsBeanPostProcessor implements BeanPostProcessor {
>   @Inject
>   ListableBeanFactory beanFactory;
>   
>   @Override
>   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
>     return bean;
>   }
>   @Override
>   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
>       if (isWebService(bean)) {
>         Bus bus = beanFactory.getBean(Bus.DEFAULT_BUS_ID, Bus.class);
>         SpringEndpointImpl endpoint = new SpringEndpointImpl(bus, bean);
>         // capitalization is just a nice feature - totally optional
>         endpoint.setAddress("/" + StringUtils.capitalize(beanName));
>         // adds ALL features registered / discovered by Spring
>         Map<String, AbstractFeature> featureMap = beanFactory.getBeansOfType(AbstractFeature.class);
>         endpoint.getFeatures().addAll(featureMap.values());
>         endpoint.publish();
>       }
>       
>       return bean;
>   }
>   boolean isWebService(Object bean) {
>     Class<?> beanClass = bean.getClass();
>     return beanClass.getAnnotation(WebService.class) != null
>         || beanClass.getAnnotation(WebServiceProvider.class) != null;
>   }
> }
> {code}
> And then if you also want to configure / inject your features using CDI (Spring) you do stuff like this (application code):
> {code:title=MyFeature.java|borderStyle=solid}
> @Named
> public class MyFeature extends AbstractFeature {
>   
>   @Inject
>   MyInInterceptor inInterceptor;
>   @Inject
>   MyOutInterceptor outInterceptor;
>   @Override
>   protected void initializeProvider(InterceptorProvider provider, Bus bus) {
>     processedBus.put(bus, Boolean.TRUE);
>     bus.getInInterceptors().add(inInterceptor);
>     bus.getOutInterceptors().add(outInterceptor);
>   }
> {code}
> Does that make sense?
> Please note that my implementation is simplified but works for me. You should probably add all other possible customizations in JaxWsBeanPostProcessor class.



--
This message was sent by Atlassian JIRA
(v6.1.4#6159)