users@jersey.java.net

Re: [Jersey] Injected into hell

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Fri, 08 Aug 2008 11:29:35 +0200

Hi Martin,

The seventh layer i suppose, sorry :-(

Try this:

   private class SessionProvider
       implements InjectableProvider<Context, Type> {

     public Injectable<Session> getInjectable(ComponentContext ic,
           Context a, Type c) {
       if (Session.class == c) {
         return new Injectable<Session>() {

           public Session getValue(HttpContext context) {
             return persistence.getSession();
           }
         };
       } else
         return null;
     }

     public Scope getScope() {
       return Scope.PerRequest;
     }
   }

It states in the JavaDoc of InjectableProvider that:

/**
  * An injectable provider provides an injectable which in turn may be used
  * to obtain the instance to inject onto a field, bean setter method,
parameter
  * of a constructor, or parameter of a method.
  *
  * @param A the annotation type
  * @param C the context type. Types of the {_at_link
java.lang.reflect.Type} and
  * {_at_link com.sun.jersey.api.model.Parameter} are the only types
that
  * are supported.
  * @author Paul.Sandoz_at_Sun.Com
  */
public interface InjectableProvider<A extends Annotation, C> {


I admit this is rather confusing. The reason for this is we need to:

1) inject parameters for @*Param that have additional meta-data e.g.
    default value and encoded, an instance of Parameter provides this
   information; and

2) not restrict the type associated with the annotation, that can be up
    to the implementation, and instance of Type provides this
    information.

So note that as this point we are not dealing with an instance of thing
to inject only the 'type' of the thing to inject. It is up to the
injectable provider to provide the instance of the 'type'. The most
efficient way i thought about this was to reuse the generic type
parameter rather than duplicate such functionality in methods.


I should probably provide a utility class that is called:

   PerRequestTypeInjectableProvider

that hides the "context type". For example:

   public abstract class PerRequestTypeInjectableProvider
         <A extends Annotation, T>
         implements InjectableProvider<A, Type> {

     private final Type t;

     /**
      * Construct a new instance with the Type and the instance.
      *
      * @param t the type of T.
      * @param instance the instance.
      */
     public PerRequestTypeInjectableProvider(Type t) {
         this.t = t;
     }

     public Scope getScope() {
         return Scope.PerRequest;
     }

     public Injectable getInjectable(ComponentContext ic, A a, Type c) {
         if (c.equals(t)) {
             return getInjectable(ic, a);
         } else
             return null;
     }

     public abstract Injectable getInjectable(ComponentContext ic, A a);
   }


Then your class would become:

   private class SessionProvider extends
       PerRequestTypeInjectableProvider<Context, Session> {

     public Injectable<Session> getInjectable(
         ComponentContext ic, Context a) {
       return new Injectable<Session>() {
         public Session getValue(HttpContext context) {
           return persistence.getSession();
         }
       };
     }

Hope this helps,
Paul.

Martin Probst wrote:
> Hi,
>
> I'm still trying to get Jersey to inject a class I provide into resource
> classes. I'm failing in more and more obscure ways. By now, I'm
> completely puzzled by the various @Context, @Inject annotations,
> Injectables and InjectableProviders ... so I'm willing to go back all
> the way, apparently I must have missed a crucial thing that has changed
> somewhen before 0.9.
>
> My problem appears to be simple, at least to me. All I want to say is
> "dear Jersey, I have this type, called org.hibernate.Session, and in
> case you're creating a Resource, and it has a field of that type, and
> it's annotated with @Inject (or whatever), please inject this instance
> which you can get from this class". This shouldn't be difficult, right?
>
> So this is the current state of the mess that used to be my application:
>
> private final class HibernatingServletContainer extends
> ServletContainer {
> @Override
> protected void initiate(ResourceConfig rc, WebApplication wa) {
> persistence = new Persistence();
> rc.getProviderInstances().add(new SessionProvider());
> super.initiate(rc, wa);
> }
> }
>
> private class SessionProvider implements InjectableProvider<Context,
> Session> {
>
> public Injectable<Session> getInjectable(ComponentContext ic,
> Context a, Session c) {
> return new Injectable<Session>() {
>
> public Session getValue(HttpContext context) {
> return persistence.getSession();
> }
> };
> }
>
> public Scope getScope() {
> return Scope.PerRequest;
> }
> }
>
> ... but Jersey doesn't even seem to learn about my SessionProvider.
>
> Also, there is apparently no example using the Injectable or Inject
> stuff - any pointers?
>
> Thanks,
> Martin
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>

-- 
| ? + ? = To question
----------------\
    Paul Sandoz
         x38109
+33-4-76188109