users@jersey.java.net

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

From: Paul Sandoz <Paul.Sandoz_at_oracle.com>
Date: Wed, 13 Oct 2010 15:18:57 +0200

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