google-code-export / google-guice

Automatically exported from code.google.com/p/google-guice
Apache License 2.0
2 stars 1 forks source link

Child Injector JIT Singletons Not Eager #386

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Similar to issue 373, but this time with implicit singletons.

Consider:

@Singleton class A { @Inject A(B b) {} }
@Singleton class B { }

AbstractModule {
 configure() {
    bind(A.class);
 }
}

If the module is used in a parent injector, B is eagerly constructed.  If
it's used in a child injector, B is not eagerly constructed.

FWIW, the patch I have attached to issue 38 can be used to fix this problem
(introducing a concept of listening to bindings, which can be used to
immediately instantiating singletons if they're supposed to be eager).

Original issue reported on code.google.com by sberlin on 11 Jun 2009 at 10:51

GoogleCodeExporter commented 9 years ago
class "A" should actually read:

@Singleton class A { @Inject A(Provider<B> b) {} }

(otherwise B is constructed as a part of A and there's no issue)

Original comment by sberlin on 11 Jun 2009 at 10:53

GoogleCodeExporter commented 9 years ago
Here's a full test that outlines four different scenarios.  Each of these pass 
when
the Injector is the parent injector, but in a child injector the last two fail.

---

package com.google.inject;

import junit.framework.TestCase;

public class ChildInjectorTest extends TestCase {

    @Override
    protected void setUp() throws Exception {
        AImpl.count = 0;
    }

    public void testExplicitEagerSingleton() {
        Guice.createInjector(Stage.PRODUCTION).createChildInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(AImpl.class);
            }
        });
        assertEquals(1, AImpl.count);
    }

    public void testLinkedEagerSingleton() {
        Guice.createInjector(Stage.PRODUCTION).createChildInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(AInter.class).to(AImpl.class);
            }
        });
        assertEquals(1, AImpl.count);
    }

    public void testImplicitEagerSingletonThroughSingleton() {
        Guice.createInjector(Stage.PRODUCTION).createChildInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(B.class).in(Scopes.SINGLETON);
            }
        });
        assertEquals(1, AImpl.count);
    }

    public void testImplicitEagerSingletonThroughUnscoped() {
        Guice.createInjector(Stage.PRODUCTION).createChildInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(B.class);
            }
        });
        assertEquals(1, AImpl.count);
    }

    @Singleton
    private static class AImpl implements AInter {
        static int count;
        AImpl() { count++; }
    }

    private static interface AInter {}

    private static class B { @Inject B(Provider<AImpl> a) {} }

}

Original comment by sberlin on 12 Jun 2009 at 2:49

GoogleCodeExporter commented 9 years ago
patch @ issue 387 solves this particular problem by listening to bindings even 
if
they're discovered after injection completes in order to create eager 
singletons.

Original comment by sberlin on 12 Jun 2009 at 3:52