users@jersey.java.net

Re: [Fwd: Re: Comment: Integrating Jersey and Spring: Take 2]

From: Martin Grotzke <martin.grotzke_at_javakaffee.de>
Date: Sat, 22 Mar 2008 19:01:17 +0100

On Wed, 2008-03-19 at 11:35 +0100, Paul Sandoz wrote:
> Martin Grotzke wrote:
> > Hi Paul,
> >
> > I think there was (is?) an issue with PerRequest scoped (spring)
> > beans/resources having a constructor with arguments. Because of that
> > (constructor) the PerRequestProvider invokes cp.getInstance(Scope,
> > Constructor, Object[]) which returned null in the prior implementation
> > of SpringComponentProvider, instead of getting the bean from spring.
> > Therefore the bean was not correctly initialized (IIRC).
> >
>
> Yes, you are correct.
>
> I do not know how to let Spring construct such resource classes.
In my case the resource (with constructor arguments) was a spring bean,
that is configured with an APIFacade passed to the constructor:

== constructor ==
publlic UsersResource( APIFacade apiFacade )

== spring bean definition ==
<bean id="usersResource" class="...UsersResource">
    <constructor-arg ref="apiFacade" />
</bean>

Therefore beanFactory.getBean( "usersResource", UsersResource.class )
returns the bean as it's configured in spring.

So the case here is that all arguments can be resolved by spring, which
is not always the case.

I want to write/sum up several use cases / scenarios of
IoC-DI/jersey-DI. To bring up one thing before: I could imagine that a
bean would be injected into a method invocation and runtime dependencies
are set within the method:

@Path("{id}/")
public UserResource getUser( @PathParam("id") final String username,
    @SpringBean UserResource result ) {
    final User user = _facade.getUserByUsername( username );
    result.setUser( user );
    return result;
}

The UserResource might then e.g. have a constructor with dependencies
that are injected by spring, additionally contain fields that are
injected by jersey, and the runtime-dependencies like that user are set
within the method.
With this approach the user would not have to cope with the
ComponentProvider and scopes in his resources classes, so this would be
the complement to returning just a class from a resource method.

Of course the @SpringBean might be s.th. different, just to denote what
is meant here :)

What do you think of this?

Cheers,
Martin




> And Richard pointed out similar problems with Guice.
>
> I did not know how to initialize such beans in Spring. BUT! I think we
> may be able to initialize such beans if and only if the constructor
> parameters are Jersey specific and Jersey instantiates (no Spring-based
> configuration for the constructor parameters). As James showed it is
> possible to support the ComponentProvider.inject method (which i left
> unimplemented):
>
> public void inject(Object object) {
> String beanName = getBeanName(object.getClass());
> if (beanName != null) {
> ConfigurableListableBeanFactory beanFactory =
> applicationContext.getBeanFactory();
> beanFactory.configureBean(object, beanName);
> }
> }
>
>
> The really hard problem is as follows:
>
> - the IoC chooses the constructor; and
>
> - there is a mixture of IoC-controled parameters and Jersey-controlled
> parameters.
>
> Paul.
>
> > Cheers,
> > Martin
> >
> >
> > On Tue, 2008-03-18 at 11:27 +0100, Paul Sandoz wrote:
> >> Hi Martin,
> >>
> >> I am replying to your comment on the users, easier to track :-)
> >>
> >> You wrote:
> >>> Just one improvement could be made to support PerRequest scoped
> >>> resources that have constructor arguments: the getInstance(Scope,
> >>> Constructor, Object[]) method (which returns null in your example)
> >>> should be changed to return getInstance( scope,
> >>> constructor.getDeclaringClass() ).
> >> The intended design was that if the ComponentProvider implementation
> >> returned null Jersey would instantiate.
> >>
> >> The WebAppicationImpl provides two implements of ComponentProvider, an
> >> adapting and default (see end of email). If a ComponentProvider is
> >> supplied by the application then it is adapted using
> >> AdaptingComponentProvider implementation, otherwise the
> >> DefaultComponentProvider is used.
> >>
> >> The WebApplicationImpl.initiate method does this:
> >>
> >> public void initiate(ResourceConfig resourceConfig,
> >> ComponentProvider provider) {
> >> ...
> >> // Set up the component provider
> >> this.provider = (provider == null)
> >> ? new DefaultComponentProvider()
> >> : new AdaptingComponentProvider(provider);
> >>
> >> Sort of a keep on trucking approach...
> >>
> >> Paul.
> >>
> >> private final class AdaptingComponentProvider implements
> >> ComponentProvider {
> >> private final ComponentProvider cp;
> >>
> >> AdaptingComponentProvider(ComponentProvider cp) {
> >> this.cp = cp;
> >> }
> >>
> >> public <T> T getInstance(Scope scope, Class<T> c)
> >> throws InstantiationException, IllegalAccessException {
> >> T o = cp.getInstance(scope,c);
> >> if (o == null)
> >> o = c.newInstance();
> >> injectResources(o);
> >> return o;
> >> }
> >>
> >> public <T> T getInstance(Scope scope, Constructor<T>
> >> contructor, Object[] parameters)
> >> throws InstantiationException, IllegalArgumentException,
> >> IllegalAccessException, InvocationTargetException {
> >> T o = cp.getInstance(scope, contructor, parameters);
> >> if (o == null)
> >> o = contructor.newInstance(parameters);
> >> injectResources(o);
> >> return o;
> >> }
> >>
> >> public void inject(Object instance) {
> >> cp.inject(instance);
> >> injectResources(instance);
> >> }
> >> }
> >>
> >> private final class DefaultComponentProvider implements
> >> ComponentProvider {
> >> public <T> T getInstance(Scope scope, Class<T> c)
> >> throws InstantiationException, IllegalAccessException {
> >> final T o = c.newInstance();
> >> injectResources(o);
> >> return o;
> >> }
> >>
> >> public <T> T getInstance(Scope scope, Constructor<T>
> >> contructor, Object[] parameters)
> >> throws InstantiationException, IllegalArgumentException,
> >> IllegalAccessException, InvocationTargetException {
> >> final T o = contructor.newInstance(parameters);
> >> injectResources(o);
> >> return o;
> >> }
> >>
> >> public void inject(Object instance) {
> >> injectResources(instance);
> >> }
> >> }
> >>
> >> email message attachment (Re: Comment: Integrating Jersey and Spring:
> >> Take 2.eml)
> >>> -------- Forwarded Message --------
> >>> From: Paul.Sandoz_at_Sun.COM
> >>> To: Paul.Sandoz_at_Sun.COM
> >>> Subject: RE: Comment: Integrating Jersey and Spring: Take 2
> >>> Date: Thu, 06 Mar 2008 11:44:27 -0800 (PST)
> >>>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> >> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>