1

I am working with guice 3 and guice-servlet 3. In the module I defined bindings of this sort:

[...]
bind(View.class).annotatedWith(Names.named("view1")).to(View1Impl.class);
bind(View.class).annotatedWith(Names.named("view2")).to(View2Impl.class);
[...]

In the injected class View1Impl I defined following:

public class View1Impl {

    @Inject @Named("view1") Provider<View> viewProvider;

    @Inject
    void init() {
        View viewA = viewProvider.get();
        View viewB = viewProvider.get();

        log.debug(viewA == viewB);
        log.debug(viewA == this);
    }

}

Both statements return true. But that should not be the case.

What am I doing wrong?

Christian
  • 3,503
  • 1
  • 26
  • 47
  • Where is your constructor, what does the `get` method do exactly? – Danyel Feb 07 '13 at 11:26
  • @Danyel There is no constructor, because I don't need a constructor. The instance gets injected. And the Provider too. see http://code.google.com/p/google-guice/wiki/InjectingProviders Do you really know what dependency injection is? Are you familiar with guice? – Christian Feb 07 '13 at 11:32
  • I am, but your example is really odd. You are recursively injecting your `Provider`. You are actually lucky that it returns the same instance (although that's somewhat odd, too), because otherwise you would get into an infinite loop. When you try: `System.out.println( injector.getInstance( View.class ) == injector.getInstance( View.class ) );`, `false` is returned. Maybe someone can explain. – Danyel Feb 07 '13 at 12:25
  • Thats my question, because I think false should be returned. But I see your point by getting into an infinite loop. I will maybe solve my problem by not eager loading the view. Maybe guice does loop detection. – Christian Feb 07 '13 at 16:09

2 Answers2

1

You might have already checked this--you've listed bindings "of the sort" you use--but it's worth double-checking that in your non-redacted code none of the classes involved are discreetly annotated with @Singleton or bound to the Singleton.class scope. Furthermore, ensure that none of your bindings use toInstance(), which will of course always return that pre-constructed instance in all cases and is effectively a singleton binding.

We had a case where we'd refactored out a bindView method and eventually forgot that we'd set it up to always bind its argument as a singleton (such that the view's parent container and view's controller could inject the same view).

Barring that, as Danyel alluded to, there is circular dependency detection coded into Guice, and since you are calling your provider.get() within a @Inject-annotated method, you may be invoking it.

Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
0

If you look inside Guice's source code, it will be clear what is actually done:

final ThreadLocal<Object[]> localContext;

/** Looks up thread local context. Creates (and removes) a new context if necessary. */
<T> T callInContext(ContextualCallable<T> callable) throws ErrorsException {
    Object[] reference = localContext.get();
    if (reference[0] == null) {
        reference[0] = new InternalContext();
        try {
            return callable.call((InternalContext)reference[0]);
        } finally {
            // Only clear the context if this call created it.
            reference[0] = null;
        }
    } else {
        // Someone else will clean up this context.
        return callable.call((InternalContext)reference[0]);
    }
}

Apparently, when your object is injected, Guice stores it in that ThreadLocal variable. Now, this according to this code snippet, it will instantly be released as it is injected. So, probably in your "scope" it is initialized somewhere else, probably at the beginning of the injection - and at the end of the injection, it is released.

Danyel
  • 2,180
  • 18
  • 32
  • I think its the circular dependency detection. I will test it tomorrow and accept your answer, cause you gave the right hint. – Christian Feb 07 '13 at 19:42
  • Yep, the problem was the infinite loop. Thx – Christian Feb 08 '13 at 08:53
  • Are you sure it is infinite loop detection and not recognition that the resource is already being reserved? As in, it is already in construct? That `reference[0]` probably was set at the start of object construction and is released at the end, so while construction it will always return the already-assigned `reference[0]`. That would be my assumption. I could be wrong. By construction, I of course mean injection. – Danyel Feb 08 '13 at 09:27
  • Probably you are right. But I fixed it, by calling teh get-Method of the Provider later, after injection. – Christian Feb 12 '13 at 08:10