[
https://issues.apache.org/jira/browse/CXF-2828?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12872256#action_12872256
]
Daniel Kulp commented on CXF-2828:
----------------------------------
OK. I definitely see the problem (very good write up). The proposed fix
isn't ideal, but definitely points in the right direction.
Basically, when calling "inject" we would like the METHODS to go through the
proxy, but the field injection needs to go to the object itself. Basic
reasoning is that their could be some "advice" attached to the methods and we'd
like to make sure that advice is followed. Thus, the fix cannot really be to
pass in the most internal object. (there is also a smaller issue of a aop
proxy of another aop proxy that needs the call to getTarget to recurse a bit)
The real fix is in ResourceInjector.java to update the call to
field.set(getTarget(), obj) to get the REAL target, and not the Proxy.
However, we don't want any spring code there so it works without the Spring
jars. Luckily, we have the ClassHelper (and the SpringClassHelper subclass
when spring AOP is available) that was easily updated to accomplish this.
I'm going to run the tests now and commit the fix (if they pass) and trigger a
new snapshot deploy. It would be great if you could test it real soon. I'm
hoping to build 2.2.9 real soon (like tomorrow even) and would like to know if
this is now fixed.
> 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
> Assignee: Daniel Kulp
>
> 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.