When I hear that a dependency depends on a runtime value I immediately think
about binding the value in scope. You can then manually seed the value
upstream before you traverse the downstream call graph.
Something like:
D d = getD();
simpleScope.seed(D.class, d);
doSomethingThatRequiresD();
...
class DependsOnD {
// Inject a provider this class is created before D is in scope
@Inject Provider<D> dProvider;
...
void useD() {
dProvider.get().doSomething();
}
}
...
// Or you might have your own scope
bind(D.class).in(RequestScoped.class);
-Fred
On Wed, Dec 8, 2010 at 7:42 PM, Ryan <[email protected]> wrote:
> Hello everyone,
>
> Been an avid user of Guice for a while now, and just ran across a new
> situation that has me stumped. I've got a dependency that I need to
> be able to change at runtime. The catch is, the piece of code that
> needs it is far down the call graph from where it changes. I've
> attempted to use assisted inject to let me customize the object at
> runtime, but there's a hitch.
>
> An example will make this more clear:
>
> class MyModule extends AbstractModule {
> protected void configure() {
>
> bind( BFactory.class ).toProvider( FactoryProvider.newFactory(
> BFactory.class,
> B.class ) );
> }
> }
>
> interface BFactory {
> B create( D d );
> }
>
> class A {
> @Inject BFactory bFac;
>
> void executeA( D d ) {
> bFac.create( d ).executeB();
> }
> }
>
> class B {
> @Inject C c;
>
> void executeB() {
> c.executeC();
> }
> }
>
> class C {
> @Inject @Assisted D d;
>
> public void executeC() {
> System.out.println( d );
> }
> }
>
> class D {};
>
> Now I can call A.executeA() with different instances of D (which is
> needed by C) at runtime. Executing the above classes with the
> following code,two different D objects are written to stdout as
> expected:
>
> A a = i.getInstance( A.class );
> a.executeA( new D() );
> a.executeA( new D() );
>
> This works as long as I only create C through the BFactory, and as
> long as everything is concrete. But if I introduce an interface,
> there's a problem, as follows:
>
> class MyModule extends AbstractModule {
> protected void configure() {
>
> bind( BFactory.class ).toProvider( FactoryProvider.newFactory(
> BFactory.class,
> B.class ) );
> bind( C.class ).to( CImpl.class );
> }
> }
>
> interface C {
> void executeC();
> }
>
> class CImpl implements C {
> @Inject @Assisted D d;
>
> public void executeC() {
> System.out.println( d );
> }
> }
>
> This gives me an error:
>
> 1) No implementation for D annotated with
> @com.google.inject.assistedinject.Assisted(value=) was bound.
> while locating D annotated with
> @com.google.inject.assistedinject.Assisted(value=)
> for field at CImpl.d(AssistedInjectTest.java:62)
> at MyModule.configure(AssistedInjectTest.java:28)
>
> The BFactory binding is still okay, but the C->CImpl binding is what
> produces the error. I assume this is because class C could
> conceivably be wired into another class as a dependency (in addition
> to class B) and Guice wouldn't know what to do with the dependency on
> D.
>
> What's the best solution to this? Am I making it needlessly complex?
> I need to know if there's a way to supply D to C without B knowing
> anything about it, while still allowing A to change what D is.
>
> Thanks,
> Ryan
>
> --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected]<google-guice%[email protected]>
> .
> For more options, visit this group at
> http://groups.google.com/group/google-guice?hl=en.
>
>
--
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice?hl=en.