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.