users@jersey.java.net

Re: [Jersey] ContainerRequestFilter as Spring component?

From: Paul Sandoz <Paul.Sandoz_at_oracle.com>
Date: Wed, 20 Oct 2010 15:52:16 +0200

Hi Mahesh,

ContainerRequest is not something that has ever been is injectable.
Before Jersey 1.3 there was no warning/errors on what is injectable or
not. Remove the field containerRequest.

For ContainerRequestFilter you don't need to inject the
ContainerRequest because it is already passed in to the filter call
i.e. it is part of the contract of the ContainerRequestFilter interface.

Paul.


On Oct 16, 2010, at 4:32 AM, Mahesh Venkat wrote:

> Hi Paul,
>
> I recently migrated from jersey-1.1.5 to jersey1.4 and I am facing
> similar issue in ContainerRequestFilter.
> I use the com.sun.jersey.spi.spring.container.servlet.SpringServlet.
>
> Until I migrated to Jersey 1.4 my code that implements
> ContainerRequestFilter was working fine. Now Isee the following
> error on the first REST invocation:
> 19:16:33,949 SEVERE [Errors] The following errors and warnings have
> been detected with resource and/or provider classes:
> SEVERE: Missing dependency for field:
> com.sun.jersey.spi.container.ContainerRequest
> com.yodlee.rest.RestContainerRequestFilter.containerRequest
> 19:16:33,949 SEVERE [SpringServlet] Exception occurred when
> intialization
> com.sun.jersey.spi.inject.Errors$ErrorMessagesException
> at
> com.sun.jersey.spi.inject.Errors.processErrorMessages(Errors.java:170)
> at com.sun.jersey.spi.inject.Errors.postProcess(Errors.java:
> 137)
> at
> com.sun.jersey.spi.inject.Errors.processWithErrors(Errors.java:203)
> at
> com
> .sun
> .jersey
> .server
> .impl
> .application.WebApplicationImpl.initiate(WebApplicationImpl.java:695)
> at
> com
> .sun
> .jersey
> .spi
> .spring.container.servlet.SpringServlet.initiate(SpringServlet.java:
> 117)
> at com.sun.jersey.spi.container.servlet.ServletContainer
> $InternalWebComponent.initiate(ServletContainer.java:287)
> at
> com
> .sun
> .jersey.spi.container.servlet.WebComponent.load(WebComponent.java:587)
> at
> com
> .sun
> .jersey.spi.container.servlet.WebComponent.init(WebComponent.java:213)
> at
> com
> .sun
> .jersey
> .spi.container.servlet.ServletContainer.init(ServletContainer.java:
> 342)
> at
> com
> .sun
> .jersey
> .spi.container.servlet.ServletContainer.init(ServletContainer.java:
> 516)
> at javax.servlet.GenericServlet.init(GenericServlet.java:212)
>
> The code snippet is ...
> @Provider
> public class RestContainerRequestFilter implements
> ContainerRequestFilter {
>
> private final static Logger logger =
> Logger.getLogger(RestContainerRequestFilter.class.getName());
>
> /**
> * <p>The URI information for this request.</p>
> */
> @Context UriInfo uriInfo;
> @Context ContainerRequest containerRequest;
> @Context HttpServletRequest httpRequest; // these are
> Threadlocal variables
> @Context HttpServletResponse httpResponse;
>
> public RestContainerRequestFilter() {}
>
> // -------override ContainerRequestFilter Methods
> -------------------------------
> @Override
> public ContainerRequest filter(@Context ContainerRequest
> containerRequest) {
> ...
> }
>
> Any clues?
>
> Appreciate your help.
>
> --Mahesh
>
>
> On Thu, Oct 14, 2010 at 6:10 AM, Nico Rehwaldt
> <nico.rehwaldt_at_web.de> 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
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>
>
>
> --
> Regards
> --Mahesh