users@jersey.java.net

Re: AW: [Jersey] ContainerRequestFilter as Spring component?

From: Paul Sandoz <Paul.Sandoz_at_oracle.com>
Date: Wed, 20 Oct 2010 17:18:30 +0200

Hi Nico,

I can reproduce now.

The problem is the call to:

         final String names[] =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(springContext, c);

It is return a zero length array when java.lang.reflect.Proxy is used.
Any ideas?

Paul.

On Oct 14, 2010, at 3:10 PM, Nico Rehwaldt wrote:

> I attached a new test case. Don’t know, what happened to the last
> one but
> the point cut was incorrect.
> This one should work. I am using Glassfish to deploy it but Tomcat
> will do
> it as well.
>
> Nico
>
> -----Ursprüngliche Nachricht-----
> Von: Paul Sandoz [mailto:Paul.Sandoz_at_oracle.com]
> Gesendet: Donnerstag, 14. Oktober 2010 11:40
> An: users_at_jersey.dev.java.net
> Betreff: Re: AW: AW: AW: [Jersey] ContainerRequestFilter as Spring
> component?
>
>
> On Oct 13, 2010, at 11:54 PM, Nico Rehwaldt wrote:
>
>> Hey Paul,
>>
>> Part 6.6 "Proxying mechanisms" in the spring reference documentation
>> ([1])
>> states
>> "Spring AOP uses either JDK dynamic proxies or CGLIB to create the
>> proxy for a given target object. (JDK dynamic proxies are preferred
>> whenever you have a choice)."
>>
>> "Having a choice" could mean that spring uses the proxy if the
>> interface mirrows the api of a class (which is the case for MyFilter
>> in my test setup).
>>
>
> Thanks, understand better now.
>
>
>> Jersey itself (as I understood it) uses the Spring component provider
>> factory to get an instance of the filter class from spring which
>> returns the java.lang.Proxy. However it cannot be handled by the
>> SpringComponentProviderFactory (which returns null then) and the
>> Filter will be instantiated for a second time (without injection
>> taking place).
>>
>
> Jersey will call the following to get an instance of the filter,
> passing in the (unproxied) Class of the filter:
>
> public IoCComponentProvider getComponentProvider(ComponentContext
> cc, Class c) {
> final Autowire autowire = (Autowire)
> c.getAnnotation(Autowire.class);
> if (autowire != null) {
> if (LOGGER.isLoggable(Level.FINEST)) {
> LOGGER.finest("Creating resource class " +
> c.getSimpleName() +
> " annotated with @" +
> Autowire.class.getSimpleName() +
> " as spring bean.");
> }
> return new SpringInstantiatedComponentProvider(c,
> autowire);
> }
>
> final String beanName = getBeanName(cc, c, springContext);
> if (beanName == null) {
> return null;
> }
>
> final String scope = findBeanDefinition(beanName).getScope();
> return new
> SpringManagedComponentProvider(getComponentScope(scope), beanName, c);
> }
>
>
>> That is the only reasonable answer for me at the moment.
>> Could you reproduce my findings with the supplied test case?
>>
>
> No. It worked for <aop:aspectj-autoproxy /> and <aop:aspectj-autoproxy
> proxy-target-class="true" />.
>
> I don't think the proxying is occurring. The following is not printed
> out in the logs:
>
> Filter executed!
>
> by the MyAspect. Is there something config missing from your attached
> app?
>
> I am using Tomcat 6.0 to deploy. What are you using?
>
> Paul.
>
>> Nico
>>
>> [1]:
>>
> http://static.springsource.org/spring/docs/2.5.x/reference/aop.html#aop-auto
>> proxy-force-CGLIB
>>
>> -----Ursprüngliche Nachricht-----
>> Von: Paul Sandoz [mailto:Paul.Sandoz_at_oracle.com]
>> Gesendet: Mittwoch, 13. Oktober 2010 15:19
>> An: users_at_jersey.dev.java.net
>> Betreff: Re: AW: AW: [Jersey] ContainerRequestFilter as Spring
>> component?
>>
>> Hi Nico,
>>
>> I cannot reproduce. The sample you attach works for me if i:
>>
>> 1) <aop:aspectj-autoproxy/> and/or
>>
>> 2) comment out the cglib dependency from the pom.
>>
>> I don't understand why a call to the Jersey Spring
>> SpringComponentProviderFactory.getComponentProvider would pass in a
>> class
>> that is of java.lang.Proxy. Since the resource filter class name is
>> registered is in the web.xml that is the class name that will be
>> used to
>> load the class and that class will be passed to the
>> pringComponentProviderFactory.getComponentProvider method. Only the
>> instance
>> looked up should be of a proxyied class.
>>
>> java.lang.Proxy only works for interfaces, so presumably it is
>> applied to
>> interfaces that are implemented by MyFilter?
>>
>> Paul.
>>
>> On Sep 24, 2010, at 10:58 AM, Nico Rehwaldt wrote:
>>
>>> Hey Paul,
>>>
>>> I confused the filter registration with the registration of resource
>>> classes, of course I register them programmatically (via
>>> com.sun.jersey.spi.container.ContainerRequestFilters init parameter
>>> in
>>> web.xml).
>>>
>>> You are right, the filter does not have to be registered as a
>>> resource
>>> class to make it work as a spring bean. The only thing which has to
>>> be
>>> changed is, that IF spring creates a proxy for a registered bean, in
>>> our case the filter, THEN it must be a CGLib proxy.
>>>
>>> In my case this happens, because I annotated the filter method with
>>> the @Transactional annotation to safely perform some database access
>>> on it.
>>> Thus, spring will create a proxy around it.
>>>
>>> I attached a test case for the problem. It contains a filter
>>> (test.MyFilter), a resource class which is injected into the filter
>>> (test.MyResource) and an Aspect which contains a pointcut on the
>>> filter method. The least is needed to force spring to create a proxy
>>> of the filter instance.
>>>
>>> If you jump into the spring configuration in src/main/resources/
>>> spring.xml you can enable usage of CGLib proxies (instead of java
>>> ones) for <aop:aspect-autoproxy /> (see [1]). With CGLib proxies
>>> used
>>> the filter works as expected, without it fails with a null pointer
>>> exception.
>>>
>>> The problem originates in the fact, that com .sun
>>> .jersey
>>> .spi.spring.container.SpringComponentProviderFactory#getBeanNa
>>> me returns null for instances of java.lang.reflect.Proxy and that
>>> therefore no IoCComponentProvider is returned for the proxy
>>> instance.
>>>
>>> Hope this helps!
>>>
>>> Nico
>>>
>>> [1]:
>>> http://static.springsource.org/spring/docs/2.5.x/reference/aop.html
>>>
>>> -----Ursprüngliche Nachricht-----
>>> Von: Paul Sandoz [mailto:Paul.Sandoz_at_oracle.com]
>>> Gesendet: Donnerstag, 23. September 2010 19:23
>>> An: users_at_jersey.dev.java.net
>>> Betreff: Re: AW: [Jersey] ContainerRequestFilter as Spring
>>> component?
>>>
>>>
>>> On Sep 22, 2010, at 4:46 PM, Nico Rehwaldt wrote:
>>>
>>>> Hey Paul,
>>>>
>>>> the filter is recognized via package scanning (not
>>>> programmatically).
>>>
>>> Filters need to be explicitly registered, as described here:
>>>
>>>
>>> https://jersey.dev.java.net/nonav/apidocs/latest/jersey/com/sun/
>>> jersey
>>> /api/c
>>> ontainer/filter/package-summary.html
>>>
>>> because ordering of filters is important. It should not be necessary
>>> for the filter to be registered in the set of classes of the
>>> resource
>>> config. So i am not sure what is going on exactly.
>>>
>>> If it is possible to wrap something up in a simple reproducible test
>>> case that would help a lot.
>>>
>>>
>>>
>>>> As the filter is annotated (and instantiated) as a spring bean, I
>>>> wondered, why it does not have any fields injected.
>>>>
>>>> However, I did some research and found out, what the problem is:
>>>> The
>>>> filter gets instantiated as a spring bean and has all fields
>>>> injected.
>>>> When Jersey wants to "use it" it will try to obtain it using the
>>>> SpringComponentProviderFactory which is registered in the
>>>> SpringServlet.
>>>> This fails and Jersey will instantiate the class (again), but on
>>>> its
>>>> own and with no injection taking place. I found two reasons for
>>>> this
>>>> behavior.
>>>>
>>>> * At first, the filter class is not registered as a ResourceClass
>>>> in
>>>> the Jersey app (I think this should happen in
>>>> SpringComponentProviderFactory#register but it only registers
>>>> provider and root resource classes). I changed the method to
>>>> accomplish this:
>>>>
>>>> private void register(ResourceConfig rc,
>>>> ConfigurableApplicationContext
>>>> springContext) {
>>>> String[] names =
>>>> BeanFactoryUtils.beanNamesIncludingAncestors(springContext);
>>>>
>>>> for (String name : names) {
>>>> Class<?> type =
>>>> ClassUtils.getUserClass(springContext.getType(name));
>>>> if (ResourceConfig.isProviderClass(type)) {
>>>> LOGGER.info("Registering Spring bean, " + name +
>>>> ", of type " + type.getName() +
>>>> " as a provider class");
>>>> rc.getClasses().add(type);
>>>> } else if (ResourceConfig.isRootResourceClass(type)) {
>>>> LOGGER.info("Registering Spring bean, " + name +
>>>> ", of type " + type.getName() +
>>>> " as a root resource class");
>>>> rc.getClasses().add(type);
>>>> } else if
>>>> (ContainerRequestFilter.class.isAssignableFrom(type))
>>>> {
>>>> LOGGER.info("Registering Spring bean, " + name +
>>>> ", of type " + type.getName() +
>>>> " as a filter class");
>>>> rc.getClasses().add(type);
>>>> }
>>>> }
>>>> }
>>>>
>>>
>>> Instead of modifying the above annotate your filter with @Provider.
>>>
>>> Paul.
>>>
>>>> * As a second problem, the filter was an instance of
>>>> java.lang.reflect.Proxy (the class name was something like $Proxy..
>>>> $).
>>>> As I read somewhere it is due to the fact, that spring uses the
>>>> java
>>>> proxies in favor of the CGLib ones, if the class has an interface
>>>> present (and the filter has). A java.lang.reflect.Proxy isn't
>>>> recognized as a bean in SpringComponentProviderFactory
>>>> #getComponentProvider(ComponentContext cc, Class c), as its bean
>>>> name
>>>> will be null. Therefore null instead of an injection provider is
>>>> returned and jersey creates the filter on its own (again).
>>>>
>>>> Everything works fine now after I forced spring to use CGLib
>>>> proxies
>>>> and made the above changes to the SpringComponentProviderFactory.
>>>>
>>>> Nico.
>>>>
>>>> -----Ursprüngliche Nachricht-----
>>>> Von: Paul Sandoz [mailto:Paul.Sandoz_at_ORACLE.COM]
>>>> Gesendet: Donnerstag, 23. September 2010 00:37
>>>> An: users_at_jersey.dev.java.net
>>>> Betreff: Re: [Jersey] ContainerRequestFilter as Spring component?
>>>>
>>>> Hi Nico,
>>>>
>>>> How are you registering the SecurityFilter with Jersey? are you
>>>> instantiating it yourself and programatically registering it?
>>>>
>>>> Paul.
>>>>
>>>> On Sep 20, 2010, at 1:16 AM, Nico Rehwaldt wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> I am using Jersey 1.4 ea together with Spring 3.0 and the jersey-
>>>>> spring integration. Integrating Jersey and Spring works fine for
>>>>> resource classes. However I created an instance of
>>>>> ContainerRequestFilter to do some pre-processing of requests. The
>>>>> filter should be a spring component and should handle setting up
>>>>> the
>>>>> security context.
>>>>>
>>>>> Basically I want to have access to the database (the ORM-Layer)
>>>>> and
>>>>> I tried to accomplish this in two ways:
>>>>>
>>>>> @Component
>>>>> public class SecurityFilter implements ContainerRequestFilter {
>>>>>
>>>>> // UserManager is a declared spring component
>>>>> // Injecting it should work somehow
>>>>> @Autowired
>>>>> private UserManager userManager;
>>>>>
>>>>> // Entity Manager would help, too
>>>>> @PersistenceContext
>>>>> private EntityManager em;
>>>>>
>>>>> @Override
>>>>> public ContainerRequest filter(ContainerRequest request) {
>>>>> System.out.println(userManager);
>>>>> // prints out null on request
>>>>> }
>>>>> }
>>>>>
>>>>> I registered the Filter as a Spring compontent, but it does not
>>>>> seem
>>>>> as if it is recognized as such.
>>>>> Both injection of EntityManager and UserManager (a Spring bean as
>>>>> well) do not work.
>>>>>
>>>>> Any suggestions what I might be doing wrong?
>>>>>
>>>>> Greetings
>>>>> Nico
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>> <jersey-containerrequestfilter-
>>> testcase
>>> .zip
>>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
> <jersey-containerrequestfilter-
> testcase
> .zip
> >---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net