Created
July 7, 2014 17:53
-
-
Save gissuebot/f4ebbcb259615c9327f6 to your computer and use it in GitHub Desktop.
Migrated attachment for Guice issue 38, comment 16
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.limewire.inject; | |
import static java.lang.annotation.ElementType.METHOD; | |
import static java.lang.annotation.ElementType.TYPE; | |
import java.lang.annotation.Retention; | |
import static java.lang.annotation.RetentionPolicy.RUNTIME; | |
import java.lang.annotation.Target; | |
import com.google.inject.Injector; | |
import com.google.inject.ScopeAnnotation; | |
/** | |
* Apply this to implementation classes when you want only one instance | |
* (per {@link Injector}) to be reused for all injections for that binding. | |
* | |
* The singleton is guaranteed to be constructed eagerly. | |
*/ | |
@Target( { TYPE, METHOD }) | |
@Retention(RUNTIME) | |
@ScopeAnnotation | |
public @interface EagerSingleton { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.limewire.inject; | |
import junit.framework.Test; | |
import org.limewire.util.BaseTestCase; | |
import com.google.inject.Guice; | |
import com.google.inject.Inject; | |
import com.google.inject.Injector; | |
import com.google.inject.Provider; | |
public class EagerSingletonTest extends BaseTestCase { | |
private static boolean EAGER_ANNOTATED_CONSTRUCTED; | |
private static boolean FOO_CONSTRUCTED; | |
public EagerSingletonTest(String name) { | |
super(name); | |
} | |
public static Test suite() { | |
return buildTestSuite(EagerSingletonTest.class); | |
} | |
@Override | |
protected void setUp() throws Exception { | |
EAGER_ANNOTATED_CONSTRUCTED = false; | |
FOO_CONSTRUCTED = false; | |
} | |
public void testEagerAnnotated() throws Exception { | |
assertFalse(EAGER_ANNOTATED_CONSTRUCTED); | |
Injector injector = Guice.createInjector(new AbstractModule() { | |
@Override | |
protected void configure() { | |
install(new LimeWireInjectModule()); | |
bind(EagerAnnotated.class); | |
} | |
}); | |
assertTrue(EAGER_ANNOTATED_CONSTRUCTED); | |
Provider<?> p = injector.getProvider(EagerAnnotated.class); | |
EagerAnnotated la = injector.getInstance(EagerAnnotated.class); | |
assertSame(la, injector.getInstance(EagerAnnotated.class)); | |
assertSame(la, p.get()); | |
} | |
public void testEagerBoundByClassAnnotation() throws Exception { | |
assertFalse(FOO_CONSTRUCTED); | |
Injector injector = Guice.createInjector(new AbstractModule() { | |
@Override | |
protected void configure() { | |
install(new LimeWireInjectModule()); | |
bind(Foo.class).in(EagerSingleton.class); | |
} | |
}); | |
assertTrue(FOO_CONSTRUCTED); | |
Provider<?> p = injector.getProvider(Foo.class); | |
Foo foo = injector.getInstance(Foo.class); | |
assertSame(foo, injector.getInstance(Foo.class)); | |
assertSame(foo, p.get()); | |
} | |
public void testEagerBoundByScope() throws Exception { | |
assertFalse(FOO_CONSTRUCTED); | |
Injector injector = Guice.createInjector(new AbstractModule() { | |
@Override | |
protected void configure() { | |
install(new LimeWireInjectModule()); | |
bind(Foo.class).in(MoreScopes.EAGER_SINGLETON); | |
} | |
}); | |
assertTrue(FOO_CONSTRUCTED); | |
Provider<?> p = injector.getProvider(Foo.class); | |
Foo foo = injector.getInstance(Foo.class); | |
assertSame(foo, injector.getInstance(Foo.class)); | |
assertSame(foo, p.get()); | |
} | |
public static void testJitFromContainerEager() { | |
Injector injector = Guice.createInjector(new AbstractModule() { | |
@Override | |
protected void configure() { | |
install(new LimeWireInjectModule()); | |
bind(Container.class); | |
} | |
}); | |
// This fails because EagerAnnotated was injected as a JIT binding, | |
// and Injector provides no way of iterating over JIT bindings. | |
assertTrue(EAGER_ANNOTATED_CONSTRUCTED); | |
} | |
public static void testJitFromInjector() { | |
Injector injector = Guice.createInjector(new AbstractModule() { | |
@Override | |
protected void configure() { | |
install(new LimeWireInjectModule()); | |
} | |
}); | |
// This fails because the TypeListener tries to create the object | |
// before the binding is ready. | |
Provider<EagerAnnotated> p = injector.getProvider(EagerAnnotated.class); | |
assertTrue(EAGER_ANNOTATED_CONSTRUCTED); | |
} | |
@EagerSingleton | |
private static class EagerAnnotated { | |
public EagerAnnotated() { | |
EAGER_ANNOTATED_CONSTRUCTED = true; | |
} | |
} | |
private static class Foo { | |
public Foo() { | |
FOO_CONSTRUCTED = true; | |
} | |
} | |
private static class Container { | |
@Inject Container(EagerAnnotated annotated) { | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.limewire.inject; | |
import java.lang.annotation.Annotation; | |
import com.google.inject.AbstractModule; | |
import com.google.inject.Binding; | |
import com.google.inject.Inject; | |
import com.google.inject.Injector; | |
import com.google.inject.Key; | |
import com.google.inject.Scope; | |
import com.google.inject.TypeLiteral; | |
import com.google.inject.matcher.Matchers; | |
import com.google.inject.spi.BindingScopingVisitor; | |
import com.google.inject.spi.TypeEncounter; | |
import com.google.inject.spi.TypeListener; | |
public class LimeWireInjectModule extends AbstractModule { | |
@Override | |
protected void configure() { | |
bindScope(LazySingleton.class, MoreScopes.LAZY_SINGLETON); | |
bindScope(EagerSingleton.class, MoreScopes.EAGER_SINGLETON); | |
TypeListener listener = new EagerCreatingListener(); | |
requestInjection(listener); | |
bindListener(Matchers.any(), listener); | |
} | |
private static class EagerCreatingListener implements TypeListener { | |
private Injector injector; | |
@Inject void injector(Injector injector) { | |
this.injector = injector; | |
for (Binding<?> b : injector.getBindings().values()) { | |
createIfEager(b); | |
} | |
} | |
@Override | |
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) { | |
if(injector != null) { | |
createIfEager(injector.getBinding(Key.get(type))); | |
} | |
} | |
private void createIfEager(final Binding<?> b) { | |
b.acceptScopingVisitor(new BindingScopingVisitor<Void>() { | |
@Override | |
public Void visitEagerSingleton() { | |
return null; | |
} | |
@Override | |
public Void visitNoScoping() { | |
return null; | |
} | |
@Override | |
public Void visitScope(Scope scope) { | |
if (scope == MoreScopes.EAGER_SINGLETON) { | |
b.getProvider().get(); | |
} | |
return null; | |
} | |
@Override | |
public Void visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) { | |
return null; | |
} | |
}); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.limewire.inject; | |
import com.google.inject.Key; | |
import com.google.inject.Provider; | |
import com.google.inject.Scope; | |
import com.google.inject.Scopes; | |
public class MoreScopes { | |
/** | |
* A singleton that will never be eager, in contrast to | |
* {@link Scopes#SINGLETON}, which Guice eagerly creates sometimes. | |
*/ | |
public static final Scope LAZY_SINGLETON = new Scope() { | |
public <T> Provider<T> scope(Key<T> key, Provider<T> creator) { | |
return Scopes.SINGLETON.scope(key, creator); | |
} | |
@Override public String toString() { | |
return "MoreScopes.LAZY_SINGLETON"; | |
} | |
}; | |
/** A singleton that will make every attempt to always be eager. */ | |
public static final Scope EAGER_SINGLETON = new Scope() { | |
public <T> Provider<T> scope(Key<T> key, Provider<T> creator) { | |
return Scopes.SINGLETON.scope(key, creator); | |
} | |
@Override public String toString() { | |
return "MoreScopes.EAGER_SINGLETON"; | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment