Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
2.2.8
-
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:
@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:
/** * 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:
/** * 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); } } }