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

                 Key: CXF-2828
                 URL: https://issues.apache.org/jira/browse/CXF-2828
             Project: CXF
          Issue Type: Bug
          Components: JAX-WS Runtime
    Affects Versions: 2.2.8
            Reporter: Oliver Geisser


h2. 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:

{code:title=SomeServiceImpl.java|borderStyle=solid}
@Transactional
@WebService(endpointInterface = "com.example.ISomeService")
public class SomeServiceImpl implements SomeService {
    @Resource
    private WebServiceContext context;
    ...

{code}

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.

h2. Background of the bug

Because the Spring {{CommonAnnotationBeanPostProcessor}} which will normally 
handle JSR-250 annotations ignores {{WebServiceContext}} {...@ressource}} 
annotations (see the Javadoc of 
[{{CommonAnnotationBeanPostProcessor}}|http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.html#ignoreResourceType%28java.lang.String%29])
  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:


{code:title=JaxWsServerFactoryBean.injectResources(Object 
instance)|borderStyle=solid}
/**
     * 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);
            }
        }
    }  
{code}

h2. 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)}}.


h2. 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:

{code:title=JaxWsServerFactoryBean.injectResources(Object instance) - 
Fixed|borderStyle=solid}
/**
     * 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);
            }
        }
    }  
{code}


-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to