users@jersey.java.net

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

From: Nico Rehwaldt <nico.rehwaldt_at_web.de>
Date: Fri, 24 Sep 2010 10:58:31 +0200

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