Re: [picocontainer-dev] Looking for advices on dynamic Component Providers

Mark Hobson <[email protected]> Tue, 7 Jul 2009 11:27:19 +0100
Newsgroups gmane.comp.java.picocontainer.devel
Message-ID <[email protected]>
I've also written an in-house abstraction layer around IoC
configuration with Pico, Spring and Guice implementations.  I
encountered the same problem when trying to support a Provider<T>
concept but simply wrote a custom adapter to implement it.  Something
like this should do the trick (off the top of my head):

public class ProviderAdapter<T> extends AbstractAdapter<T> {
    private final Provider<T> provider;
    public ProviderAdapter(Object key, Class<T> implementation,
Provider<T> provider) {
        super(key, implementation);
        this.provider = provider;
    }
    public T getComponentInstance(PicoContainer container, Type into)
throws PicoCompositionException {
        return provider.get();
    }
    public void verify(PicoContainer container) throws
PicoCompositionException {
        return true;
    }
    public String getDescriptor() {
        return "ProviderAdapter";
    }
}

Mark

2009/7/6 Fabio Kung <[email protected]>:
> Hi all,
> I'm involved in a project which needs to be independent from IoC vendors. We
> ended building a thin anti-corruption layer which translates our needs to
> several IoC providers and we already have implementations for Pico and
> Spring, with Guice coming.
> My problem appeared when trying to support what we call
> "ComponentFactories". I believe Pico calls them "Providers". Here is a small
> example:
> @Component // causes it to be registered in the container
> public class HibernateProvider implements ComponentFactory<Session> {
>   private SessionFactory factory;
>   public HibernateProvider(SessionFactory regularConstructorInjection) {
>     // this component is managed, then it may receive any available
> dependency
>   }
>   public Session getInstance() {
>     // this is similar to a Pico's provide() method
>     return ...; // hibernate session for current scope
>   }
> }
> We are doing a work very similar to what JSR-330 (Dependency Injection for
> Java) is trying to achieve, abstracting IoC providers. Hopefully, I also
> believe that some of you guys are involved in this JSR and probably had (or
> will have to) deal with the same problem, because the spec has a Provider<T>
> interface.
> My idea is to register a ProviderAdapter inside Pico, for each
> ComponentFactory. The main issue is that Pico statically checks for the
> Provider targetType, taking the return type of the provide() method. So, it
> would require a new class for each ComponentFactory, as every associated
> ProviderAdapter must have a provide() method with a different return type.
> I know I could use ASM and build a new ProviderAdapter class at runtime for
> each ComponentFactory, with a different provide() method. But I really
> wanted to avoid dealing with ASM, bytecode manipulation and ClassLoaders if
> it could be solved in an easier manner.
> Then, my second thought was to create a "generic ProviderAdapter" for Pico,
> that doesn't require target types to be specified as return types of
> provide() methods. It simply receives the target type as a regular
> dependency:
> public class GenericProviderAdapter implements Injector, Adapter {
>    private static final Method provideMethod;
>     static {
>         try {
>             provideMethod =
> ComponentFactoryAdapter.class.getMethod("provide", Container.class);
>         } catch (NoSuchMethodException e) {
>             throw new ExceptionInInitializerError(e);
>         }
>     }
>     private final Class<? extends ComponentFactory> factoryType;
>     private final Class<?> targetType;
>     public GenericProviderAdapter(Class<? extends ComponentFactory>
> factoryType) {
>         this.factoryType = factoryType;
>         // not relevant and specific to my case, but I'm taking the
> targetType from
>         // the generic type definition: XYZ implements
> ComponentFactory<Session> => targetType = Session.class
>         this.targetType = new
> ComponentFactoryIntrospector().targetTypeFor(factoryType);
>     }
>     public Object provide(Container container) {
>         // the ComponentFactory is managed, then I need the container to
> retrieve an instance
>         // note: Container interface is implemented with Pico in this
> example
>         return container.instanceFor(factoryType).getInstance();
>     }
>     public Object getComponentInstance(PicoContainer container, Type into)
> throws PicoCompositionException {
>         return new Reinjector(container).reinject(targetType,
> this.getClass(), this, Characteristics.NONE, new
> MethodInjection(provideMethod));
>     }
>     // ...
> }
> My idea is that for every ComponentFactory in the application, one
> ProviderAdapter is registered inside pico:
>   pico.addComponent(new GenericProviderAdapter(componentFactoryType));
> The important pieces of the GenericProviderAdapter are:
>   - the return type of the provide() method is generic (Object), so that I
> can use the same ProviderAdapter for every ComponentFactory;
>   - the getComponentInstance() method is based on the original code from
> ProviderAdapter class, but it infers the targetType of the Provider from the
> ComponentFactory class, instead of using the return type of the provide()
> method.
> It is almost working, despite the fact that Pico has a type check for
> Provider classes in the AbstractAdapter#checkTypeCompatibility() method. The
> type check throws an exception when the provide() method return type differs
> from the actual targetType, that is my case.
>   protected void checkTypeCompatibility() {
>     // ...
>     if (Provider.class.isAssignableFrom(componentImplementation)) {
>       if (!componentType.isAssignableFrom(
>
>  ProviderAdapter.getProvideMethod(componentImplementation).getReturnType()))
> {
>         throw newCCE(componentType);
>       }
>     }
>     // ...
>   }
> Would you mind relaxing the type check? Or does someone have an alternative
> idea/approach?
> By now, I'm just building custom implementations of all Injectors involved
> in the process (ReInjector, MethodInjection, MethodInjector and
> MethodInjector$ByReflectionMethod), overriding the checkTypeCompatibility()
> method. I had to override all injectors, because the type check is being
> called at _every_ injector instantiation (as the call is in the
> AbstractAdapter constructor).
> It would be much easier if you could just drop (or change) the type check
> inside the AbstractAdapter class. Do you think it is reasonable?
> I think it would also be useful to people implementing JSR-330 (which has
> the Provider<T> interface), JSR-299 (which has Producer<T> interface) and
> others, on top of Pico. All of them could be easily mapped one-to-one to a
> Pico GenericProducerAdapter instance, without requiring class generation at
> runtime.
> Thanks!
> Cheers,
> --
> Fabio Kung
> http://www.fabiokung.com
>
> Caelum - Ensino e Inovação
> http://www.caelum.com.br
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email