Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-2828

JSR 250 @Resource annotation on field does not work for proxied service implementations

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 2.2.8
    • 2.2.9
    • JAX-WS Runtime
    • None

    Description

      Description

      A JAX-WS service implementation class has a private WebServiceContext field which is annotated with the JSR-250 @Resource annotation. It has also some annotation - for example @Transactional - which will make Spring wrapping it with a proxy. See the following code for an example:

      SomeServiceImpl.java
      @Transactional
      @WebService(endpointInterface = "com.example.ISomeService")
      public class SomeServiceImpl implements SomeService {
          @Resource
          private WebServiceContext context;
          ...
      
      

      In the current release (2.2.8) this does not work and throws an IllegalArgumentException.

      BTW There is the workaround to annotate a setter method instead of annotating the field.

      Background of the bug

      Because the Spring CommonAnnotationBeanPostProcessor which will normally handle JSR-250 annotations ignores WebServiceContext @Ressource annotations (see the Javadoc of CommonAnnotationBeanPostProcessor) there needs to be a special handling inside of CXF. This special handling happens in the org.apache.cxf.jaxws.JaxWsServerFactoryBean.injectResources(Object instance) method:

      JaxWsServerFactoryBean.injectResources(Object instance)
      /**
           * inject resources into servant.  The resources are injected
           * according to @Resource annotations.  See JSR 250 for more
           * information.
           */
          /**
           * @param instance
           */
          protected void injectResources(Object instance) {
              if (instance != null) {
                  ResourceManager resourceManager = getBus().getExtension(ResourceManager.class);
                  List<ResourceResolver> resolvers = resourceManager.getResourceResolvers();
                  resourceManager = new DefaultResourceManager(resolvers); 
                  resourceManager.addResourceResolver(new WebServiceContextResourceResolver());
                  ResourceInjector injector = new ResourceInjector(resourceManager);
                  if (Proxy.isProxyClass(instance.getClass()) && getServiceClass() != null) {
                      injector.inject(instance, getServiceClass());
                      injector.construct(instance, getServiceClass());
                  } else {
                      injector.inject(instance);
                      injector.construct(instance);
                  }
              }
          }  
      

      Bug

      As you can see there is already a special case to detect a proxy (Proxy.isProxyClass()). The bug is that even in the case of a proxy the code tries to inject into the field of the proxy. But the proxy does not have the field and this gives an IllegalArgumentException inside of ResourceInjector.injectField(Field field, Object resource).

      Fix

      In the case of a proxied object find the "wrapped" (target) object and inject into this object. This is possible because the proxy will be a Spring proxy and Spring has a special Interface (Advised) which will allow to access the target object. See the following code:

      JaxWsServerFactoryBean.injectResources(Object instance) - Fixed
      /**
           * inject resources into servant.  The resources are injected
           * according to @Resource annotations.  See JSR 250 for more
           * information.
           */
          /**
           * @param instance
           */
          protected void injectResources(Object instance) {
              if (instance != null) {
                  ResourceManager resourceManager = getBus().getExtension(ResourceManager.class);
                  List<ResourceResolver> resolvers = resourceManager.getResourceResolvers();
                  resourceManager = new DefaultResourceManager(resolvers); 
                  resourceManager.addResourceResolver(new WebServiceContextResourceResolver());
                  ResourceInjector injector = new ResourceInjector(resourceManager);
                  if (Proxy.isProxyClass(instance.getClass()) && getServiceClass() != null) {
      
                      // FIXED: find and inject into the proxy target
                      Object proxyTarget = ((org.springframework.aop.framework.Advised)instance).getTargetSource().getTarget();
                      injector.inject(proxyTarget, getServiceClass());
      
                      injector.construct(instance, getServiceClass());
                  } else {
                      injector.inject(instance);
                      injector.construct(instance);
                  }
              }
          }  
      

      Attachments

        Activity

          People

            dkulp Daniel Kulp
            ogeisser Oliver Geisser
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: