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

Fabio Kung <[email protected]> Tue, 7 Jul 2009 12:17:23 -0300
Newsgroups gmane.comp.java.picocontainer.devel
Message-ID <[email protected]>
Thanks guys. I ended up solving the issue as Mark did.

I didn't realize I could directly use a custom ComponentAdapter,
completely avoiding pico Providers. (although I think it would be more
natural to use pico providers).

On Tue, Jul 7, 2009 at 7:27 AM, Mark Hobson<[email protected]> wrote:
> 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
>
>
>



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