Discussion:
Silly question: can I pass my own parameters for object instantiantion?
Andre Costa
2008-10-25 16:33:58 UTC
Permalink
Hi,

... this is probably a silly question, please bear with the newbie ;-)

I'm trying to learn how to use PicoContainer for a presentation about IoC
and Dependency Injection frameworks I'm preparing, and so far I think I
understood the main points. However, I have one major doubt that's been
bugging me: is it possible to pass external objects to be used by a
container as parameters for the instantiation of another object?

Eg. considering the Juicer class on [
http://www.picocontainer.org/introduction.html], suppose I need to create a
Juicer with my own instance of a Peeler (eg. a modified clone of an
instance) instead of letting the container create a new one for me, or use a
cached one. It would be something like:

pico.getComponent(Juicer.class, myPeelerInstance);

as if this by this I could tell the container that it should use the
received object as one of the parameters for the construction of Juicer
instead of trying itself to create a Peeler.

Is this possible anyway? Am I going the wrong way here?

This question came to mind when I thought of one scenario that happens in
one of our applications, in which ObjectA that receives ObjectB and
manipulates (changes) it sometimes (depending on the situation) receives a
clone of an instance of ObjectB so that changes can be discarded if desired
after the manipulation ends.

I hope I made myself clear, please let me know if any further details are
needed.

Regards,

Andre
Konstantin Priblouda
2008-10-25 18:13:05 UTC
Permalink
----[ Konstantin Pribluda http://www.pribluda.de ]----------------
JTec quality components: http://www.pribluda.de/projects/
Subject: [picocontainer-user] Silly question: can I pass my own parameters for object instantiantion?
Date: Saturday, October 25, 2008, 7:33 PM
Hi,
... this is probably a silly question, please bear with the
newbie ;-)
I'm trying to learn how to use PicoContainer for a
presentation about IoC
and Dependency Injection frameworks I'm preparing, and
so far I think I
understood the main points. However, I have one major doubt
that's been
bugging me: is it possible to pass external objects to be
used by a
container as parameters for the instantiation of another
object?
Eg. considering the Juicer class on [
http://www.picocontainer.org/introduction.html], suppose I
need to create a
Juicer with my own instance of a Peeler (eg. a modified
clone of an
instance) instead of letting the container create a new one
for me, or use a
pico.getComponent(Juicer.class, myPeelerInstance);
AFAIR, current API does not provide means for that usage scenario.
However, you could achive this by some swindling with component adapters
backed by some external storage ( like JNDI ) , or even write your own.


regards,




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

http://xircles.codehaus.org/manage_email
Andre Costa
2008-10-27 16:43:21 UTC
Permalink
Hi Konstantin,
Post by Konstantin Priblouda
----[ Konstantin Pribluda http://www.pribluda.de ]----------------
JTec quality components: http://www.pribluda.de/projects/
Subject: [picocontainer-user] Silly question: can I pass my own
parameters for object instantiantion?
Date: Saturday, October 25, 2008, 7:33 PM
Hi,
... this is probably a silly question, please bear with the
newbie ;-)
I'm trying to learn how to use PicoContainer for a
presentation about IoC
and Dependency Injection frameworks I'm preparing, and
so far I think I
understood the main points. However, I have one major doubt
that's been
bugging me: is it possible to pass external objects to be
used by a
container as parameters for the instantiation of another
object?
Eg. considering the Juicer class on [
http://www.picocontainer.org/introduction.html], suppose I
need to create a
Juicer with my own instance of a Peeler (eg. a modified
clone of an
instance) instead of letting the container create a new one
for me, or use a
pico.getComponent(Juicer.class, myPeelerInstance);
AFAIR, current API does not provide means for that usage scenario.
However, you could achive this by some swindling with component adapters
backed by some external storage ( like JNDI ) , or even write your own.
Thks for the ideas. I took a look at AbstractAdapter, but I must confess I
didn't get much further, I still could not understand a clever way to do
what I want using it. Also, IMHO going this way would mean going long ways
just to do what I need to do... I was really hoping for something simpler =(

(I'll comment Paul's suggestions on a separate message)

Regards,

Andre
Konstantin Priblouda
2008-10-27 18:29:16 UTC
Permalink
Post by Andre Costa
Thks for the ideas. I took a look at AbstractAdapter, but I
must confess I
didn't get much further, I still could not understand a
clever way to do
what I want using it. Also, IMHO going this way would mean
going long ways
just to do what I need to do... I was really hoping for
something simpler =(
Take any adapter backed by object reference, and keep this reference -
then you can tweak it whenever you like.

regards,




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

http://xircles.codehaus.org/manage_email
Paul Hammant
2008-10-26 11:53:47 UTC
Permalink
Andre,

The simplest way would be

MutablePicoContainer pico = new DefaultPicoContainer();
pico.addComponent(Apple.class);
pico.addComponent(Juicer.class);
pico.addComponent(myPeelerInstance);
Juicer juicer = (Juicer) pico.getComponent(Juicer.class);

The problem with this though is that it will use the same
myPeelerInstance for each call to getComponent() regardless of whether
caching it on for the container or not.

you could instead have

MutablePicoContainer parent = new DefaultPicoContainer(new Caching());
parent.addComponent(Apple.class);
MutablePicoContainer transientPico = new DefaultPicoContainer(parent);
transientPico.addComponent(Juicer.class);
transientPico.addComponent(myPeelerInstance);
Juicer juicer = (Juicer) transientPico.getComponent(Juicer.class);
// then discard the transientPico

There are perhaps more sophisticated ways, but i think the above case
may be what you want. Tell me if I misunderstand though.

- Paul
Post by Andre Costa
Hi,
... this is probably a silly question, please bear with the newbie ;-)
I'm trying to learn how to use PicoContainer for a presentation
about IoC and Dependency Injection frameworks I'm preparing, and so
far I think I understood the main points. However, I have one major
doubt that's been bugging me: is it possible to pass external
objects to be used by a container as parameters for the
instantiation of another object?
Eg. considering the Juicer class on [http://www.picocontainer.org/introduction.html
], suppose I need to create a Juicer with my own instance of a
Peeler (eg. a modified clone of an instance) instead of letting the
container create a new one for me, or use a cached one. It would be
pico.getComponent(Juicer.class, myPeelerInstance);
as if this by this I could tell the container that it should use the
received object as one of the parameters for the construction of
Juicer instead of trying itself to create a Peeler.
Is this possible anyway? Am I going the wrong way here?
This question came to mind when I thought of one scenario that
happens in one of our applications, in which ObjectA that receives
ObjectB and manipulates (changes) it sometimes (depending on the
situation) receives a clone of an instance of ObjectB so that
changes can be discarded if desired after the manipulation ends.
I hope I made myself clear, please let me know if any further
details are needed.
Regards,
Andre
Paul Hammant
2008-10-26 15:56:33 UTC
Permalink
Andre,

Another way is illustrated in ProviderTestCase : http://svn.codehaus.org/picocontainer/java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ProviderTestCase.java
See providedTypeCanBeDyanamicallyDeterminedFromInstanceRatherThanType().

ExampleRequestReader in this case is going to pull an imaginary
'chocolate' parameter from a HttpServletRequest which is going to
change per request and definately 'external' by your definition. In
this case ExampleRequestReader designed to be reusable.

The minima for your case could be :-

public static class PeelerProvider extends ProviderAdapter {

public Class getComponentImplementation() {
return Peeler.class;
}

public Object provide() {
return myPeelerInstance;
}

This is much more like Guice's Provider mechanism, but goes further as
the provide method can ask for more deps from PicoContainer that it is
in.

Regards,

- Paul
Post by Paul Hammant
Andre,
The simplest way would be
MutablePicoContainer pico = new DefaultPicoContainer();
pico.addComponent(Apple.class);
pico.addComponent(Juicer.class);
pico.addComponent(myPeelerInstance);
Juicer juicer = (Juicer) pico.getComponent(Juicer.class);
The problem with this though is that it will use the same
myPeelerInstance for each call to getComponent() regardless of
whether caching it on for the container or not.
you could instead have
MutablePicoContainer parent = new DefaultPicoContainer(new Caching());
parent.addComponent(Apple.class);
MutablePicoContainer transientPico = new DefaultPicoContainer(parent);
transientPico.addComponent(Juicer.class);
transientPico.addComponent(myPeelerInstance);
Juicer juicer = (Juicer) transientPico.getComponent(Juicer.class);
// then discard the transientPico
There are perhaps more sophisticated ways, but i think the above
case may be what you want. Tell me if I misunderstand though.
- Paul
Post by Andre Costa
Hi,
... this is probably a silly question, please bear with the
newbie ;-)
I'm trying to learn how to use PicoContainer for a presentation
about IoC and Dependency Injection frameworks I'm preparing, and so
far I think I understood the main points. However, I have one major
doubt that's been bugging me: is it possible to pass external
objects to be used by a container as parameters for the
instantiation of another object?
Eg. considering the Juicer class on [http://www.picocontainer.org/introduction.html
], suppose I need to create a Juicer with my own instance of a
Peeler (eg. a modified clone of an instance) instead of letting the
container create a new one for me, or use a cached one. It would be
pico.getComponent(Juicer.class, myPeelerInstance);
as if this by this I could tell the container that it should use
the received object as one of the parameters for the construction
of Juicer instead of trying itself to create a Peeler.
Is this possible anyway? Am I going the wrong way here?
This question came to mind when I thought of one scenario that
happens in one of our applications, in which ObjectA that receives
ObjectB and manipulates (changes) it sometimes (depending on the
situation) receives a clone of an instance of ObjectB so that
changes can be discarded if desired after the manipulation ends.
I hope I made myself clear, please let me know if any further
details are needed.
Regards,
Andre
Paul Hammant
2008-10-26 16:03:08 UTC
Permalink
Correction ..
Post by Paul Hammant
public static class PeelerProvider extends ProviderAdapter {
public Peeler provide() {
return myPeelerInstance;
}
}
.. is the minimal version.

- Paul
Post by Paul Hammant
Andre,
Another way is illustrated in ProviderTestCase : http://svn.codehaus.org/picocontainer/java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ProviderTestCase.java
See
providedTypeCanBeDyanamicallyDeterminedFromInstanceRatherThanType().
ExampleRequestReader in this case is going to pull an imaginary
'chocolate' parameter from a HttpServletRequest which is going to
change per request and definately 'external' by your definition. In
this case ExampleRequestReader designed to be reusable.
The minima for your case could be :-
public static class PeelerProvider extends ProviderAdapter {
public Class getComponentImplementation() {
return Peeler.class;
}
public Object provide() {
return myPeelerInstance;
}
This is much more like Guice's Provider mechanism, but goes further
as the provide method can ask for more deps from PicoContainer that
it is in.
Regards,
- Paul
Post by Paul Hammant
Andre,
The simplest way would be
MutablePicoContainer pico = new DefaultPicoContainer();
pico.addComponent(Apple.class);
pico.addComponent(Juicer.class);
pico.addComponent(myPeelerInstance);
Juicer juicer = (Juicer) pico.getComponent(Juicer.class);
The problem with this though is that it will use the same
myPeelerInstance for each call to getComponent() regardless of
whether caching it on for the container or not.
you could instead have
MutablePicoContainer parent = new DefaultPicoContainer(new
Caching());
parent.addComponent(Apple.class);
MutablePicoContainer transientPico = new
DefaultPicoContainer(parent);
transientPico.addComponent(Juicer.class);
transientPico.addComponent(myPeelerInstance);
Juicer juicer = (Juicer) transientPico.getComponent(Juicer.class);
// then discard the transientPico
There are perhaps more sophisticated ways, but i think the above
case may be what you want. Tell me if I misunderstand though.
- Paul
Post by Andre Costa
Hi,
... this is probably a silly question, please bear with the
newbie ;-)
I'm trying to learn how to use PicoContainer for a presentation
about IoC and Dependency Injection frameworks I'm preparing, and
so far I think I understood the main points. However, I have one
major doubt that's been bugging me: is it possible to pass
external objects to be used by a container as parameters for the
instantiation of another object?
Eg. considering the Juicer class on [http://www.picocontainer.org/introduction.html
], suppose I need to create a Juicer with my own instance of a
Peeler (eg. a modified clone of an instance) instead of letting
the container create a new one for me, or use a cached one. It
pico.getComponent(Juicer.class, myPeelerInstance);
as if this by this I could tell the container that it should use
the received object as one of the parameters for the construction
of Juicer instead of trying itself to create a Peeler.
Is this possible anyway? Am I going the wrong way here?
This question came to mind when I thought of one scenario that
happens in one of our applications, in which ObjectA that receives
ObjectB and manipulates (changes) it sometimes (depending on the
situation) receives a clone of an instance of ObjectB so that
changes can be discarded if desired after the manipulation ends.
I hope I made myself clear, please let me know if any further
details are needed.
Regards,
Andre
Andre Costa
2008-10-27 18:36:16 UTC
Permalink
Hi Paul,
Post by Paul Hammant
Correction ..
public static class PeelerProvider extends ProviderAdapter {
public Peeler provide() {
return myPeelerInstance;
}
}
.. is the minimal version.
- Paul
Andre,
http://svn.codehaus.org/picocontainer/java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ProviderTestCase.java
See providedTypeCanBeDyanamicallyDeterminedFromInstanceRatherThanType().
ExampleRequestReader in this case is going to pull an imaginary 'chocolate'
parameter from a HttpServletRequest which is going to change per request and
definately 'external' by your definition. In this
case ExampleRequestReader designed to be reusable.
The minima for your case could be :-
public static class PeelerProvider extends ProviderAdapter {
public Class getComponentImplementation() {
return Peeler.class;
}
public Object provide() {
return myPeelerInstance;
}
This is much more like Guice's Provider mechanism, but goes further as the
provide method can ask for more deps from PicoContainer that it is in.
Regards,
- Paul
Andre,
The simplest way would be
1. MutablePicoContainer pico = new DefaultPicoContainer();
2. pico.addComponent(Apple.class);
3. pico.addComponent(Juicer.class);
4. pico.addComponent(myPeelerInstance);
5. Juicer juicer = (Juicer) pico.getComponent(Juicer.class);
The problem with this though is that it will use the same myPeelerInstance
for each call to getComponent() regardless of whether caching it on for the
container or not.
you could instead have
1. MutablePicoContainer parent = new DefaultPicoContainer(new
Caching());
2. parent.addComponent(Apple.class);
1. MutablePicoContainer transientPico = new DefaultPicoContainer(parent);
1. transientPico.addComponent(Juicer.class);
2. transientPico.addComponent(myPeelerInstance);
3. Juicer juicer = (Juicer) transientPico.getComponent(Juicer.class);
4. // then discard the transientPico
There are perhaps more sophisticated ways, but i think the above case may
be what you want. Tell me if I misunderstand though.
- Paul
Thks a lot for the suggestions. All of them would indeed help me, at
different costs.

Ideally I would be able to write my own (generic) container that would be
able to hot-swap components on the fly, throwing them away after being used,
and I would make it a child of the default container; Eg. something like
this:

ContainerWithParams extends DefaultPicoContainer {
// FIXME synchronize this method?
public Object getComponentWithParams(Object key, Object... params) {
// register params as components on this container, so that they
have
// precedence over parent's components
for (Object param : params) {
// FIXME doesn't work: there's no way we can guarantee that
// this instance of param will be used when an object of this
type is needed
addComponent(param);
}
Object result = getComponent(key);
// now remove params so that they don't persist across calls
for (Object param : params) {
removeComponent(param);
}
return result;
}
}

This way, if use MyContainer.getComponent() I would get default behavior
(i.e. object would be instantiated as usual). However, if I use
getComponentWithParams() I would temporarily "inject" component instances on
the container so that they would be used instead of the ones registered on
the default container, and would also be removed before the call ends, so
that there would be no side-effects on calls to plain getComponent().

Main problem is that AFAICS there's no way to ensure that asking MyContainer
for one of the params will return the recently-registered objects. One way
to ensure this would require a multi-step approach, since each parameter
would need to be registered with its own key before the call. But this would
start making this solution less appealing... =(

I could also do something more specific, along the line you suggested:

MyJuicerContainer extends DefaultPicoContainer {
private MutablePicoContainer parent;

MyJuicerContainer(PicoContainer parent, Peeler peelerInstance) {
this.parent = parent;
addComponent(Peeler.class, peelerInstance);
}

@Override
public Object getComponent(Object key, Object implOrInstance,
Parameter...
parameters) {
parent.addChildContainer(this);
Object result = getComponent(key);
parent.removeChildContainer(this);
return result;
}
}

BTW: I wouldn't use parent.addChild() ... parent.removeChild() on each call
to getComponent() if there's a way to make sure each instance of MyContainer
will be removed from the container hierarchy when it's not used anymore.

(... I just hope I am making *any* sense ;-))

Regards,

Andre
Paul Hammant
2008-10-27 18:50:27 UTC
Permalink
Just a quicke for now, take a look at http://picocontainer.org/behaviors.html#hasi
Hot Swapping.

More later.

Regards,

- Paul
Post by Andre Costa
Hi Paul,
Correction ..
Post by Paul Hammant
public static class PeelerProvider extends ProviderAdapter {
public Peeler provide() {
return myPeelerInstance;
}
}
.. is the minimal version.
- Paul
Post by Paul Hammant
Andre,
Another way is illustrated in ProviderTestCase : http://svn.codehaus.org/picocontainer/java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ProviderTestCase.java
See
providedTypeCanBeDyanamicallyDeterminedFromInstanceRatherThanType().
ExampleRequestReader in this case is going to pull an imaginary
'chocolate' parameter from a HttpServletRequest which is going to
change per request and definately 'external' by your definition.
In this case ExampleRequestReader designed to be reusable.
The minima for your case could be :-
public static class PeelerProvider extends ProviderAdapter {
public Class getComponentImplementation() {
return Peeler.class;
}
public Object provide() {
return myPeelerInstance;
}
This is much more like Guice's Provider mechanism, but goes further
as the provide method can ask for more deps from PicoContainer that
it is in.
Regards,
- Paul
Post by Paul Hammant
Andre,
The simplest way would be
MutablePicoContainer pico = new DefaultPicoContainer();
pico.addComponent(Apple.class);
pico.addComponent(Juicer.class);
pico.addComponent(myPeelerInstance);
Juicer juicer = (Juicer) pico.getComponent(Juicer.class);
The problem with this though is that it will use the same
myPeelerInstance for each call to getComponent() regardless of
whether caching it on for the container or not.
you could instead have
MutablePicoContainer parent = new DefaultPicoContainer(new
Caching());
parent.addComponent(Apple.class);
MutablePicoContainer transientPico = new
DefaultPicoContainer(parent);
transientPico.addComponent(Juicer.class);
transientPico.addComponent(myPeelerInstance);
Juicer juicer = (Juicer) transientPico.getComponent(Juicer.class);
// then discard the transientPico
There are perhaps more sophisticated ways, but i think the above
case may be what you want. Tell me if I misunderstand though.
- Paul
Thks a lot for the suggestions. All of them would indeed help me, at
different costs.
Ideally I would be able to write my own (generic) container that
would be able to hot-swap components on the fly, throwing them away
after being used, and I would make it a child of the default
ContainerWithParams extends DefaultPicoContainer {
// FIXME synchronize this method?
public Object getComponentWithParams(Object key, Object...
params) {
// register params as components on this container, so that
they have
// precedence over parent's components
for (Object param : params) {
// FIXME doesn't work: there's no way we can guarantee that
// this instance of param will be used when an object of
this type is needed
addComponent(param);
}
Object result = getComponent(key);
// now remove params so that they don't persist across calls
for (Object param : params) {
removeComponent(param);
}
return result;
}
}
This way, if use MyContainer.getComponent() I would get default
behavior (i.e. object would be instantiated as usual). However, if I
use getComponentWithParams() I would temporarily "inject" component
instances on the container so that they would be used instead of the
ones registered on the default container, and would also be removed
before the call ends, so that there would be no side-effects on
calls to plain getComponent().
Main problem is that AFAICS there's no way to ensure that asking
MyContainer for one of the params will return the recently-
registered objects. One way to ensure this would require a multi-
step approach, since each parameter would need to be registered with
its own key before the call. But this would start making this
solution less appealing... =(
MyJuicerContainer extends DefaultPicoContainer {
private MutablePicoContainer parent;
MyJuicerContainer(PicoContainer parent, Peeler peelerInstance) {
this.parent = parent;
addComponent(Peeler.class, peelerInstance);
}
@Override
public Object getComponent(Object key, Object implOrInstance,
Parameter...
parameters) {
parent.addChildContainer(this);
Object result = getComponent(key);
parent.removeChildContainer(this);
return result;
}
}
BTW: I wouldn't use parent.addChild() ... parent.removeChild() on
each call to getComponent() if there's a way to make sure each
instance of MyContainer will be removed from the container hierarchy
when it's not used anymore.
(... I just hope I am making *any* sense ;-))
Regards,
Andre
Andre Costa
2008-10-27 19:31:08 UTC
Permalink
Hi Paul, thks again, will take a look at it soon. BTW: I just realized my
question might not be that silly after all: Guice also had to address this
;-) Take a look at

http://code.google.com/p/google-guice/wiki/Guice10Recipes
(search for "How do I pass a parameter when creating an object via Guice?")

and

http://groups.google.com/group/google-guice/browse_thread/thread/9a7e2c57583d21d6

Regards,

Andre
Post by Paul Hammant
Just a quicke for now, take a look at
http://picocontainer.org/behaviors.html#hasi Hot Swapping.
More later.
Regards,
- Paul
Hi Paul,
Post by Paul Hammant
Correction ..
public static class PeelerProvider extends ProviderAdapter {
public Peeler provide() {
return myPeelerInstance;
}
}
.. is the minimal version.
- Paul
Andre,
http://svn.codehaus.org/picocontainer/java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ProviderTestCase.javaSee providedTypeCanBeDyanamicallyDeterminedFromInstanceRatherThanType().
ExampleRequestReader in this case is going to pull an imaginary
'chocolate' parameter from a HttpServletRequest which is going to change per
request and definately 'external' by your definition. In this
case ExampleRequestReader designed to be reusable.
The minima for your case could be :-
public static class PeelerProvider extends ProviderAdapter {
public Class getComponentImplementation() {
return Peeler.class;
}
public Object provide() {
return myPeelerInstance;
}
This is much more like Guice's Provider mechanism, but goes further as the
provide method can ask for more deps from PicoContainer that it is in.
Regards,
- Paul
Andre,
The simplest way would be
1. MutablePicoContainer pico = new DefaultPicoContainer();
2. pico.addComponent(Apple.class);
3. pico.addComponent(Juicer.class);
4. pico.addComponent(myPeelerInstance);
5. Juicer juicer = (Juicer) pico.getComponent(Juicer.class);
The problem with this though is that it will use the same myPeelerInstance
for each call to getComponent() regardless of whether caching it on for the
container or not.
you could instead have
1. MutablePicoContainer parent = new DefaultPicoContainer(new
Caching());
2. parent.addComponent(Apple.class);
1. MutablePicoContainer transientPico = new DefaultPicoContainer(parent);
1. transientPico.addComponent(Juicer.class);
2. transientPico.addComponent(myPeelerInstance);
3. Juicer juicer = (Juicer) transientPico.getComponent(Juicer.class);
4. // then discard the transientPico
There are perhaps more sophisticated ways, but i think the above case may
be what you want. Tell me if I misunderstand though.
- Paul
Thks a lot for the suggestions. All of them would indeed help me, at
different costs.
Ideally I would be able to write my own (generic) container that would be
able to hot-swap components on the fly, throwing them away after being used,
and I would make it a child of the default container; Eg. something like
ContainerWithParams extends DefaultPicoContainer {
// FIXME synchronize this method?
public Object getComponentWithParams(Object key, Object... params) {
// register params as components on this container, so that they
have
// precedence over parent's components
for (Object param : params) {
// FIXME doesn't work: there's no way we can guarantee that
// this instance of param will be used when an object of this
type is needed
addComponent(param);
}
Object result = getComponent(key);
// now remove params so that they don't persist across calls
for (Object param : params) {
removeComponent(param);
}
return result;
}
}
This way, if use MyContainer.getComponent() I would get default behavior
(i.e. object would be instantiated as usual). However, if I use
getComponentWithParams() I would temporarily "inject" component instances on
the container so that they would be used instead of the ones registered on
the default container, and would also be removed before the call ends, so
that there would be no side-effects on calls to plain getComponent().
Main problem is that AFAICS there's no way to ensure that asking
MyContainer for one of the params will return the recently-registered
objects. One way to ensure this would require a multi-step approach, since
each parameter would need to be registered with its own key before the call.
But this would start making this solution less appealing... =(
MyJuicerContainer extends DefaultPicoContainer {
private MutablePicoContainer parent;
MyJuicerContainer(PicoContainer parent, Peeler peelerInstance) {
this.parent = parent;
addComponent(Peeler.class, peelerInstance);
}
@Override
public Object getComponent(Object key, Object implOrInstance,
Parameter...
parameters) {
parent.addChildContainer(this);
Object result = getComponent(key);
parent.removeChildContainer(this);
return result;
}
}
BTW: I wouldn't use parent.addChild() ... parent.removeChild() on each call
to getComponent() if there's a way to make sure each instance of MyContainer
will be removed from the container hierarchy when it's not used anymore.
(... I just hope I am making *any* sense ;-))
Regards,
Andre
Andre Costa
2008-10-28 13:48:20 UTC
Permalink
Hi Paul,
Post by Paul Hammant
Just a quicke for now, take a look at
http://picocontainer.org/behaviors.html#hasi Hot Swapping.
More later.
Regards,
- Paul
As far as I can see, HotSwapping would probably spare me from having to
create a child container and allow me to do all the magic on the main
(default) container, using swap() instead of addComponent() for the external
object.

However, the main problem would still be the fact that I cannot guarantee
that, unless I provide the proper pair (key, instance) for each external
object, I will actually replace the Peeler component that will be used for
Juicer creation by the container instead of registering *another* Peeler
(which would totally miss the point). And I'm not blaming PicoContainer for
that, I think it's legitimate that it needs to know exactly what it should
replace.

Maybe something like this could work:

public class RuntimeParameter {
public Object key;
public Object instance;

public RuntimeParameter(Object key, Object instance) {
this.key = key;
this.instance = instance;
}
}

public class ContainerWithParams extends DefaultPicoContainer {

@Override
public Object getComponent(Object key, RuntimeParameter... params) {
Map<Object, Object> originalValues = new HashMap<Object, Object>();
for (RuntimeParameter rtp : params) {
HotSwappable hs = (HotSwappable)
pico.getComponentAdapter(rtp.key);
Object oldValue = hs.getSwappable().swap(rtp.instance);
if (oldValue != null) {
originalValues.put(rtp.key, oldValue);
}
}
Object component = getComponent(key);
for (Map.Entry<Object, Object> entry : originalValues.entrySet()) {
HotSwappable hs = (HotSwappable)
pico.getComponentAdapter(entry.getKey());
hs.getSwappable().swap(entry.getValue());
}
return component;
}
}

and it would be used as in:

Juicer juicer = containerWithParams.getComponent(Juicer.class, new
RuntimeParameter(Peeler.class, peelerInstance));

It's still more cumbersome than I'd like (due to the need to use
RuntimeParameter), but AFAICS it manages to solve the problem generically.

Regards,

Andre
Post by Paul Hammant
Hi Paul,
Post by Paul Hammant
Correction ..
public static class PeelerProvider extends ProviderAdapter {
public Peeler provide() {
return myPeelerInstance;
}
}
.. is the minimal version.
- Paul
Andre,
http://svn.codehaus.org/picocontainer/java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ProviderTestCase.javaSee providedTypeCanBeDyanamicallyDeterminedFromInstanceRatherThanType().
ExampleRequestReader in this case is going to pull an imaginary
'chocolate' parameter from a HttpServletRequest which is going to change per
request and definately 'external' by your definition. In this
case ExampleRequestReader designed to be reusable.
The minima for your case could be :-
public static class PeelerProvider extends ProviderAdapter {
public Class getComponentImplementation() {
return Peeler.class;
}
public Object provide() {
return myPeelerInstance;
}
This is much more like Guice's Provider mechanism, but goes further as the
provide method can ask for more deps from PicoContainer that it is in.
Regards,
- Paul
Andre,
The simplest way would be
1. MutablePicoContainer pico = new DefaultPicoContainer();
2. pico.addComponent(Apple.class);
3. pico.addComponent(Juicer.class);
4. pico.addComponent(myPeelerInstance);
5. Juicer juicer = (Juicer) pico.getComponent(Juicer.class);
The problem with this though is that it will use the same myPeelerInstance
for each call to getComponent() regardless of whether caching it on for the
container or not.
you could instead have
1. MutablePicoContainer parent = new DefaultPicoContainer(new
Caching());
2. parent.addComponent(Apple.class);
1. MutablePicoContainer transientPico = new DefaultPicoContainer(parent);
1. transientPico.addComponent(Juicer.class);
2. transientPico.addComponent(myPeelerInstance);
3. Juicer juicer = (Juicer) transientPico.getComponent(Juicer.class);
4. // then discard the transientPico
There are perhaps more sophisticated ways, but i think the above case may
be what you want. Tell me if I misunderstand though.
- Paul
Thks a lot for the suggestions. All of them would indeed help me, at
different costs.
Ideally I would be able to write my own (generic) container that would be
able to hot-swap components on the fly, throwing them away after being used,
and I would make it a child of the default container; Eg. something like
ContainerWithParams extends DefaultPicoContainer {
// FIXME synchronize this method?
public Object getComponentWithParams(Object key, Object... params) {
// register params as components on this container, so that they
have
// precedence over parent's components
for (Object param : params) {
// FIXME doesn't work: there's no way we can guarantee that
// this instance of param will be used when an object of this
type is needed
addComponent(param);
}
Object result = getComponent(key);
// now remove params so that they don't persist across calls
for (Object param : params) {
removeComponent(param);
}
return result;
}
}
This way, if use MyContainer.getComponent() I would get default behavior
(i.e. object would be instantiated as usual). However, if I use
getComponentWithParams() I would temporarily "inject" component instances on
the container so that they would be used instead of the ones registered on
the default container, and would also be removed before the call ends, so
that there would be no side-effects on calls to plain getComponent().
Main problem is that AFAICS there's no way to ensure that asking
MyContainer for one of the params will return the recently-registered
objects. One way to ensure this would require a multi-step approach, since
each parameter would need to be registered with its own key before the call.
But this would start making this solution less appealing... =(
MyJuicerContainer extends DefaultPicoContainer {
private MutablePicoContainer parent;
MyJuicerContainer(PicoContainer parent, Peeler peelerInstance) {
this.parent = parent;
addComponent(Peeler.class, peelerInstance);
}
@Override
public Object getComponent(Object key, Object implOrInstance,
Parameter...
parameters) {
parent.addChildContainer(this);
Object result = getComponent(key);
parent.removeChildContainer(this);
return result;
}
}
BTW: I wouldn't use parent.addChild() ... parent.removeChild() on each call
to getComponent() if there's a way to make sure each instance of MyContainer
will be removed from the container hierarchy when it's not used anymore.
(... I just hope I am making *any* sense ;-))
Regards,
Andre
Andre Costa
2008-10-28 13:53:06 UTC
Permalink
Post by Andre Costa
Hi Paul,
Post by Paul Hammant
Just a quicke for now, take a look at
http://picocontainer.org/behaviors.html#hasi Hot Swapping.
More later.
Regards,
- Paul
As far as I can see, HotSwapping would probably spare me from having to
create a child container and allow me to do all the magic on the main
(default) container, using swap() instead of addComponent() for the external
object.
However, the main problem would still be the fact that I cannot guarantee
that, unless I provide the proper pair (key, instance) for each external
object, I will actually replace the Peeler component that will be used for
Juicer creation by the container instead of registering *another* Peeler
(which would totally miss the point). And I'm not blaming PicoContainer for
that, I think it's legitimate that it needs to know exactly what it should
replace.
public class RuntimeParameter {
public Object key;
public Object instance;
public RuntimeParameter(Object key, Object instance) {
this.key = key;
this.instance = instance;
}
}
public class ContainerWithParams extends DefaultPicoContainer {
@Override
public Object getComponent(Object key, RuntimeParameter... params) {
Map<Object, Object> originalValues = new HashMap<Object, Object>();
for (RuntimeParameter rtp : params) {
HotSwappable hs = (HotSwappable)
pico.getComponentAdapter(rtp.key);
Object oldValue = hs.getSwappable().swap(rtp.instance);
if (oldValue != null) {
originalValues.put(rtp.key, oldValue);
}
}
Object component = getComponent(key);
for (Map.Entry<Object, Object> entry : originalValues.entrySet()) {
HotSwappable hs = (HotSwappable)
pico.getComponentAdapter(entry.getKey());
hs.getSwappable().swap(entry.getValue());
}
return component;
}
}
Juicer juicer = containerWithParams.getComponent(Juicer.class, new
RuntimeParameter(Peeler.class, peelerInstance));
It's still more cumbersome than I'd like (due to the need to use
RuntimeParameter), but AFAICS it manages to solve the problem generically.
Regards,
Andre
Paul Hammant
2008-10-29 17:00:17 UTC
Permalink
Andre,

I'm pretty convinced that the use case you have can be solved by
adding addAdapter(..) with a subclass of ProviderAdapter (or one of
the related techniques). This new feature is somewhere between
Guice's providers and it's "assisted inject" capability.

Peelers can be reliably set dynamically for new Juicers with this.

myPeelerAdapter = new ProviderAdapter() {
public Peeler provide() {
return myPeeler;
}
}

...

MutablePicoContainer pico = new DefaultPicoContainer();
pico.addComponent(Apple.class);
pico.as(NO_CACHE).addComponent(Juicer.class);
pico.addAdapter(myPeelerAdapter);

...

Juicer juicer = pico.getComponent(Juicer.class)

being an inner class, myPeeler must be final or a member-variable. It
could be thread-local derived, or set by a setter if this is not
called by multiple threads concurrently.

Regards,

- Paul
Post by Andre Costa
Hi Paul,
Just a quicke for now, take a look at http://picocontainer.org/behaviors.html#hasi
Hot Swapping.
More later.
Regards,
- Paul
As far as I can see, HotSwapping would probably spare me from having
to create a child container and allow me to do all the magic on the
main (default) container, using swap() instead of addComponent() for
the external object.
However, the main problem would still be the fact that I cannot
guarantee that, unless I provide the proper pair (key, instance) for
each external object, I will actually replace the Peeler component
that will be used for Juicer creation by the container instead of
registering *another* Peeler (which would totally miss the point).
And I'm not blaming PicoContainer for that, I think it's legitimate
that it needs to know exactly what it should replace.
public class RuntimeParameter {
public Object key;
public Object instance;
public RuntimeParameter(Object key, Object instance) {
this.key = key;
this.instance = instance;
}
}
public class ContainerWithParams extends DefaultPicoContainer {
@Override
public Object getComponent(Object key, RuntimeParameter...
params) {
Map<Object, Object> originalValues = new HashMap<Object, Object>();
for (RuntimeParameter rtp : params) {
HotSwappable hs = (HotSwappable)
pico.getComponentAdapter(rtp.key);
Object oldValue = hs.getSwappable().swap(rtp.instance);
if (oldValue != null) {
originalValues.put(rtp.key, oldValue);
}
}
Object component = getComponent(key);
originalValues.entrySet()) {
HotSwappable hs = (HotSwappable)
pico.getComponentAdapter(entry.getKey());
hs.getSwappable().swap(entry.getValue());
}
return component;
}
}
Juicer juicer = containerWithParams.getComponent(Juicer.class, new
RuntimeParameter(Peeler.class, peelerInstance));
It's still more cumbersome than I'd like (due to the need to use
RuntimeParameter), but AFAICS it manages to solve the problem
generically.
Regards,
Andre
Witold Szczerba
2008-10-27 22:48:16 UTC
Permalink
Hi there,
what I say might sound silly :) but, following your example, maybe you
could just ask container to return juicer and then you could provide
your unique peeler instance by injecting it manually, so instead of:

pico.getComponent(Juicer.class, myPeelerInstance);

you could write:
Juicer juicer = pico.getComponent(Juicer.class);

//and now either:
juicer.setPeeler(myPeelerInstance);
juicer.doSomething()...
//or
juicer.doSomething(myPeelerInstance)...

Regards,
Witold Szczerba
Post by Andre Costa
Hi,
... this is probably a silly question, please bear with the newbie ;-)
I'm trying to learn how to use PicoContainer for a presentation about IoC
and Dependency Injection frameworks I'm preparing, and so far I think I
understood the main points. However, I have one major doubt that's been
bugging me: is it possible to pass external objects to be used by a
container as parameters for the instantiation of another object?
Eg. considering the Juicer class on
[http://www.picocontainer.org/introduction.html], suppose I need to create a
Juicer with my own instance of a Peeler (eg. a modified clone of an
instance) instead of letting the container create a new one for me, or use a
pico.getComponent(Juicer.class, myPeelerInstance);
as if this by this I could tell the container that it should use the
received object as one of the parameters for the construction of Juicer
instead of trying itself to create a Peeler.
Is this possible anyway? Am I going the wrong way here?
This question came to mind when I thought of one scenario that happens in
one of our applications, in which ObjectA that receives ObjectB and
manipulates (changes) it sometimes (depending on the situation) receives a
clone of an instance of ObjectB so that changes can be discarded if desired
after the manipulation ends.
I hope I made myself clear, please let me know if any further details are
needed.
Regards,
Andre
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Andre Costa
2008-10-28 11:57:14 UTC
Permalink
Hi Witold,
Post by Witold Szczerba
Hi there,
what I say might sound silly :) but, following your example, maybe you
could just ask container to return juicer and then you could provide
pico.getComponent(Juicer.class, myPeelerInstance);
Juicer juicer = pico.getComponent(Juicer.class);
juicer.setPeeler(myPeelerInstance);
juicer.doSomething()...
//or
juicer.doSomething(myPeelerInstance)...
Regards,
Witold Szczerba
Thks, it's indeed an option, and I had already considered this. The main
problems are:

- I'd rather have this whole operation more encapsulated, so that forgetting
to call the setter wouldn't be an issue (the second approach you suggested
kind of fixes this, though)
- sometimes creating the object that will later be replaced by the injected
instance can be a non-trivial task, and so I'd rather not have to create one
just to throw it away

Regards,

Andre
Post by Witold Szczerba
Post by Andre Costa
Hi,
... this is probably a silly question, please bear with the newbie ;-)
I'm trying to learn how to use PicoContainer for a presentation about IoC
and Dependency Injection frameworks I'm preparing, and so far I think I
understood the main points. However, I have one major doubt that's been
bugging me: is it possible to pass external objects to be used by a
container as parameters for the instantiation of another object?
Eg. considering the Juicer class on
[http://www.picocontainer.org/introduction.html], suppose I need to
create a
Post by Andre Costa
Juicer with my own instance of a Peeler (eg. a modified clone of an
instance) instead of letting the container create a new one for me, or
use a
Post by Andre Costa
pico.getComponent(Juicer.class, myPeelerInstance);
as if this by this I could tell the container that it should use the
received object as one of the parameters for the construction of Juicer
instead of trying itself to create a Peeler.
Is this possible anyway? Am I going the wrong way here?
This question came to mind when I thought of one scenario that happens in
one of our applications, in which ObjectA that receives ObjectB and
manipulates (changes) it sometimes (depending on the situation) receives
a
Post by Andre Costa
clone of an instance of ObjectB so that changes can be discarded if
desired
Post by Andre Costa
after the manipulation ends.
I hope I made myself clear, please let me know if any further details are
needed.
Regards,
Andre
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
Witold Szczerba
2008-10-28 13:13:08 UTC
Permalink
Hello,
I would still prefer not to play with DI container and choose no magic
(but maybe I am wrong)...
I think, you could ask container for JuicerFactory instead of Juicer
itself, which would have 2 methods:
#getJuicer()
#getJuicer(myPeelerInstance)
The first one would create juicer with default peeler, the second one
would use your custom peeler.
The implementation could look like this:

public class JuicerFactory {

public Juicer getJuicer() {
Peeler peeler = ...get default peeler from pico
return getJuicer(peeler);
}
public Juicer getJuicer(Peeler peeler) {
Juicer result = ...get juicer with no peeler from pico
result.setPeeler(peeler);
return result;
}
}
Peeler is now injected manually but this is happening only in one
place. That approach would eliminate two problems you pointed before:
1) the operation of acquiring peeler is encapsulated - you cannot
forget to set custom peeler, your juicer is always ready-to-go
2) there is no need to create default peeler if you want provide custom one

I do not use DI container so I do not know how, but you could also do
something additional, not to be able to get juicer from Pico in other
parts of application. You would always ask for JuicerFactory instead.
What do you think?

Witold Szczerba
Post by Andre Costa
Hi Witold,
- I'd rather have this whole operation more encapsulated, so that forgetting
to call the setter wouldn't be an issue (the second approach you suggested
kind of fixes this, though)
- sometimes creating the object that will later be replaced by the injected
instance can be a non-trivial task, and so I'd rather not have to create one
just to throw it away
Regards,
Andre
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Loading...