users@jersey.java.net

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

From: Nico Rehwaldt <nico.rehwaldt_at_web.de>
Date: Wed, 13 Oct 2010 23:54:43 +0200

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).

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).

That is the only reasonable answer for me at the moment.
Could you reproduce my findings with the supplied test case?

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