|
View:
New views
4 Messages
—
Rating Filter:
Alert me
|
|
|
Looking for advices on dynamic Component ProvidersHi 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! |
|
|
Re: Looking for advices on dynamic Component ProvidersHi Fabio,
On Jul 6, 2009, at 1:19 PM, Fabio Kung wrote: > 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. Provider<T> is very different from a full abstracted DI layer in the JDK. > > 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? Perhaps. Send us a testcase that is an elegant demo of the feature you;re needing. > > 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. OK, so there's one more thing about ProviderAdapter ... if you override getComponentImplementation() you can ( I think ) bypass the typecheck for the return of the provide(..) method. Look at the last inner class in ProviderTestCase. - Paul --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: Looking for advices on dynamic Component ProvidersI'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 <fabio.kung@...>: > 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 |
|
|
Re: Looking for advices on dynamic Component ProvidersThanks 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<markhobson@...> 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 <fabio.kung@...>: >> 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 |
| Free embeddable forum powered by Nabble | Forum Help |