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